zoukankan      html  css  js  c++  java
  • luogu CF708C Centroids 换根dp好题

    //以u为根节点
    //找u的最大子树 中的最大分支
    //直接连到u上
    //看看能不能满足条件
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int N = 400010;
    struct Node
    {
    	int fi, se;
    	void insert(int x) // 向最大值和次大值中插入一个值
    	{
    		if (x > fi)
    		{
    			se = fi;
    			fi = x;
    		}
    		else if (x > se)
    			se = x;
    	}
    	int get(int x) // 得到除了 x 外的最大值
    	{
    		if (x == fi)
    			return se;
    		else
    			return fi;
    	}
    } dn[N];
    int h[N], ne[N<<1], e[N << 1], idx;
    int n, siz[N], fa[N], son[N], up[N];
    int calc(int u)
    {
    	return siz[u] <= n / 2 ? siz[u] : dn[u].fi;
    }
    void dfs1(int u)
    {
    	siz[u] = 1;
    	for (int i = h[u]; ~i; i = ne[i])
    	{
    		int v = e[i];
    		if (v == fa[u])
    			continue;
    		fa[v] = u;
    		dfs1(v);
    		//以这个点为根的所有子树的大小的和
    		siz[u] += siz[v];
    		//以这个点为根的最大和次大子树的大小
    		dn[u].insert(calc(v));
    	}
    }
    void dfs2(int u)
    {
    	//除了以当前点为根的子树的节点的个数
    	//也就说 上面的不会产生负面影响,直接插进去就好
    	if (n - siz[u] <= n / 2)
    		up[u] = n - siz[u];
    	//也就是说,除了当前子树,剩下的点的个数大于n/2
    	else
    		//		父节点再网上的分支,
    		//						父节点中,除了当前的子树,其他最大的子树中最大的分支
    		up[u] = max(up[fa[u]], dn[fa[u]].get(calc(u)));
    	for (int i = h[u]; ~i; i = ne[i])
    	{
    		int v = e[i];
    		if (v == fa[u])
    			continue;
    		dfs2(v);
    		if (siz[v] > siz[son[u]])
    			son[u] = v; // son 是一个节点的最大子树
    	}
    	//如果最大的分支,是上面的节点,那么节记录
    	if (n - siz[u] > siz[son[u]])
    		son[u] = fa[u];
    }
    //以这个点为根节点的树,如果总的节点数<=n/2,那么就不会对父节点产生负面影响
    //如果大于了,那么就需要找到最大的子树,方便删掉
    void add(int a, int b)
    {
    	e[idx]=b;
    	ne[idx]=h[a];
    	h[a]=idx++;
    }
    int main()
    {
    	memset(h,-1,sizeof h);
    	cin>>n;
    	for (int i = 1; i < n; ++i)
    	{
    		int u,v;
    		scanf("%d%d", &u, &v);
    		add(u, v);
    		add(v, u);
    	}
    	dfs1(1);
    	dfs2(1);
    	//以当前点为根节点
    	for (int u = 1; u <= n; ++u)
    	{
    		int mx, sz;
    		int v = son[u];
    		//如果最大的分支,是除了 当前点往下所有点+当前点 的点
    		//其他的点 是通过父节点 父节点再和这个点相连
    		//那么此时 就要找到与父节点相连的最大分支,也就是up[u]
    		//直接与u相连,
    		if (v == fa[u])
    		{
    			//上面点的个数,不包括当前的点
    			sz = n - siz[u];
    			//最大子树中,不包括当前子树,最大的分支
    			mx = up[u]; // 也可以 max(dn[v].get(calc(u)), up[v])
    		}
    		else
    		{
    			sz = siz[v];
    			mx = dn[v].fi;
    		}
    		printf("%d ", sz - mx <= n / 2);
    	}
    	return 0;
    }
    
  • 相关阅读:
    斐波那契数列 详解
    ASP.NET 系列:RBAC权限设计
    架构系列:ASP.NET 项目结构搭建
    EntityFramework系列:Repository模式与单元测试
    PHP 系列:PHP Web 开发基础
    Java Web系列:Spring Boot 基础
    ddddddd
    ddd
    asdfsf
    sdfsdfsdf
  • 原文地址:https://www.cnblogs.com/QingyuYYYYY/p/12834068.html
Copyright © 2011-2022 走看看