zoukankan      html  css  js  c++  java
  • CF600E Lomsat gelral 树上启发式合并

    题目描述

    有一棵 (n) 个结点的以 (1) 号结点为根的有根树。
    每个结点都有一个颜色,颜色是以编号表示的, (i) 号结点的颜色编号为 (c_i)​。
    如果一种颜色在以 (x) 为根的子树内出现次数最多,称其在以 (x) 为根的子树中占主导地位。显然,同一子树中可能有多种颜色占主导地位。
    你的任务是对于每一个 (iin[1,n]),求出以 (i) 为根的子树中,占主导地位的颜色的编号和。
    (n≤10^5,c_ile n)

    输入输出样例

    输入 #1

    4
    1 2 3 4
    1 2
    2 3
    2 4

    输出 #1

    10 9 3 4

    输入 #2

    15
    1 2 3 1 2 3 3 1 1 3 2 2 1 2 3
    1 2
    1 3
    1 4
    1 14
    1 15
    2 5
    2 6
    2 7
    3 8
    3 9
    3 10
    4 11
    4 12
    4 13

    输出 #2

    6 5 4 3 2 3 3 1 1 3 2 2 1 2 3

    分析

    DSU ON TREE洛谷日报
    对于这一道题,因为一个子树递归结束后产生的影响会传递给下一个子树
    所以在每一次计算之前都要清空贡献
    但是这样做时间复杂度吃不消
    其实 (dfs) 时有一个性质
    对于一个节点,它所递归的最后一个子树的价值是不用清空的
    而我们要尽量使这个子树保留的信息更多
    因此我们选择这个节点的重儿子进行递归
    对于轻儿子暴力删除和加入
    复杂度证明请看洛谷日报

    代码

    #include<cstdio>
    #include<cstring>
    inline int read(){
    	register int x=0,fh=1;
    	char ch=getchar();
    	while(ch<'0' || ch>'9'){
    		if(ch=='-') fh=-1;
    		ch=getchar();
    	}
    	while(ch>='0' && ch<='9'){
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return x*fh;
    }
    const int maxn=2e5+5;
    int h[maxn],tot=1;
    struct asd{
    	int to,nxt;
    }b[maxn];
    void ad(int aa,int bb){
    	b[tot].to=bb;
    	b[tot].nxt=h[aa];
    	h[aa]=tot++;
    }
    int n,c[maxn],f[maxn],son[maxn],siz[maxn];
    void dfs(int now,int fa){
    	siz[now]=1;
    	f[now]=fa;
    	for(register int i=h[now];i!=-1;i=b[i].nxt){
    		register int u=b[i].to;
    		if(u==fa) continue;
    		dfs(u,now);
    		siz[now]+=siz[u];
    		if(son[now]==0 || siz[son[now]]<siz[u]){
    			son[now]=u;
    		}
    	}
    }
    //求出每一个节点的重儿子
    int cnt[maxn],orz;
    long long sum,mmax,ans[maxn];
    void xg(int now,int val){
    	cnt[c[now]]+=val;
    	if(cnt[c[now]]>mmax){
    		mmax=cnt[c[now]];
    		sum=c[now];
    	} else if(cnt[c[now]]==mmax){
    		sum+=c[now];
    	}
    	for(int i=h[now];i!=-1;i=b[i].nxt){
    		int u=b[i].to;
    		if(u==f[now] || u==orz) continue;
    		xg(u,val);
    	}
    }
    //删除/加入贡献
    void dfs2(int now,int op){
    	for(register int i=h[now];i!=-1;i=b[i].nxt){
    		register int u=b[i].to;
    		if(u==f[now] || u==son[now]) continue;
    		dfs2(u,0);
    	}
    	if(son[now]){
    		dfs2(son[now],1);
    		orz=son[now];
    	} 
    	xg(now,1);
    	orz=0;
    	ans[now]=sum;
    	if(op==0){
    		xg(now,-1);
    		sum=mmax=0;
    	}
    }
    //求出答案
    int main(){
    	memset(h,-1,sizeof(h));
    	n=read();
    	for(register int i=1;i<=n;i++){
    		c[i]=read();
    	}
    	int aa,bb;
    	for(register int i=1;i<n;i++){
    		aa=read(),bb=read();
    		ad(aa,bb);
    		ad(bb,aa);
    	}
    	dfs(1,0);
    	dfs2(1,0);
    	for(register int i=1;i<=n;i++){
    		printf("%lld ",ans[i]);
    	}
    	printf("
    ");
    	return 0;
    }
    
  • 相关阅读:
    父级和 子集 controller 之间的通讯
    ui-router(三)controller与template
    ui-router详解(二)ngRoute工具区别
    关于MySql全文索引
    Yii提供的Htmler助手checkboxList可自定义Checkbox输出格式
    添加和删除索引以及如何给中间表添加两个主键
    设置数据库及表的默认字符集
    保存数据的时候报类型错误的原因和解决方案
    金融经济
    YII获取刚插入数据的id主键
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/13775626.html
Copyright © 2011-2022 走看看