• CodeForces


    ( ext{Description})

    传送门

    ( ext{Solution})

    好妙啊。

    显然统计了 (u) 为根子树后要清空才能统计它的兄弟,我们尝试加一些小小的优化。

    预处理出轻重儿子,由于如果一个儿子是最后遍历的就不用清空,直观地我们选择重儿子最后遍历。

    如何证明时间复杂度?考虑一个点到根的链上最多只有 (log n) 条轻边。因为一条轻边意味着节点的父亲的 (siz) 大于此节点 (siz) 的两倍,所以一条轻边 (siz) 就会乘以 (2),最多只能乘 (log n) 次。

    而一个节点只会被改到根的链上的轻边条数次(因为重儿子不被清空),时间复杂度 (mathcal O(nlog n))

    ( ext{Code})

    #include <cstdio>
    #include <vector>
    using namespace std;
    typedef long long ll;
    
    const int maxn=1e5+5;
    
    int n,c[maxn],f[maxn],tot[maxn],siz[maxn],son[maxn],maxx;
    ll ans[maxn],sum;
    bool vis[maxn];
    vector <int> e[maxn];
    
    void dfs1(int u,int fa) {
    	f[u]=fa,siz[u]=1;
    	for(int i=0;i<e[u].size();++i) {
    		if(e[u][i]==fa) continue;
    		dfs1(e[u][i],u);
    		siz[u]+=siz[e[u][i]];
    		if(siz[e[u][i]]>siz[son[u]]) son[u]=e[u][i];
    	}
    }
    
    void calc(int u,int k) {
    	tot[c[u]]+=k;
    	if(tot[c[u]]>maxx) maxx=tot[c[u]],sum=c[u];
    	else if(tot[c[u]]==maxx) sum+=c[u];
    	for(int i=0;i<e[u].size();++i)
    		if(!vis[e[u][i]]&&e[u][i]!=f[u])
    			calc(e[u][i],k);
    }
    
    void dfs2(int u,int Keep) {
    	for(int i=0;i<e[u].size();++i) if(e[u][i]!=son[u]&&e[u][i]!=f[u]) dfs2(e[u][i],0);
    	if(son[u]) vis[son[u]]=1,dfs2(son[u],1);
    	calc(u,1); ans[u]=sum;
    	if(son[u]) vis[son[u]]=0;
    	if(!Keep) calc(u,-1),sum=maxx=0;
    }
    
    int main() {
    	scanf("%d",&n);
    	for(int i=1;i<=n;++i) scanf("%d",&c[i]);
    	for(int i=1;i<n;++i) {
    		int x,y;
    		scanf("%d %d",&x,&y);
    		e[x].push_back(y),e[y].push_back(x);
    	}
    	dfs1(1,0); dfs2(1,1);
    	for(int i=1;i<=n;++i) printf("%lld ",ans[i]); puts("");
    	return 0;
    } 
    
  • 相关阅读:
    MvvmTest
    win8 app 相关的几个网站
    autp
    分析WPF代码工具
    mdsn
    线程和委托
    C#guanli
    学习Boost小结(一)
    Boost.test库的配置
    自己真是太没正事了.
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/14279964.html
Copyright © 2020-2023  润新知