CF600E Lomsat gelral && CF741D【DSU on Tree】

CF600E

题目描述:

树上每个点有个颜色,记子树内出现次数最多的颜色的出现次数为 c n t cnt cnt,求子树中出现次数为 c n t cnt cnt的颜色的编号和。对每个子树都要算。
n ≤ 100000 n\le100000 n100000

题目分析:

DSU on Tree板题。
存桶,先做轻儿子,清空,再做重儿子,不清空,加入轻儿子,算答案,return。

也可以对每个颜色建虚树dfs求出虚树上点的标记,最后做一遍dfs从下往上合并贡献。

也可以线段树合并。

Code:

#include<bits/stdc++.h>
#define maxn 100005
#define LL long long
#define ADJ(i,u) for(int i=fir[u],v;i;i=nxt[i])
using namespace std;
int n,siz[maxn],son[maxn],c[maxn];
int fir[maxn],nxt[maxn<<1],to[maxn<<1],tot;
void line(int x,int y){nxt[++tot]=fir[x],fir[x]=tot,to[tot]=y;}
void dfs1(int u,int ff){
	siz[u]=1;
	ADJ(i,u) if((v=to[i])!=ff)
		dfs1(v,u),siz[u]+=siz[v],siz[v]>siz[son[u]]&&(son[u]=v);
}
int cnt[maxn],num;
LL sum,ans[maxn];
void clear(int u,int ff){
	cnt[c[u]]--;
	ADJ(i,u) if((v=to[i])!=ff) clear(v,u);
}
void add(int c){
	if(++cnt[c]>num) num=cnt[c],sum=c;
	else if(cnt[c]==num) sum+=c;
}
void Add(int u,int ff){
	add(c[u]);
	ADJ(i,u) if((v=to[i])!=ff) Add(v,u);
}
void dfs2(int u,int ff){
	ADJ(i,u) if((v=to[i])!=ff&&v!=son[u]) dfs2(v,u),clear(v,u),sum=num=0;
	if(son[u]) dfs2(son[u],u);
	ADJ(i,u) if((v=to[i])!=ff&&v!=son[u]) Add(v,u);
	add(c[u]),ans[u]=sum;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&c[i]);
	for(int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),line(x,y),line(y,x);
	dfs1(1,0),dfs2(1,0);
	for(int i=1;i<=n;i++) printf("%lld%c",ans[i],i==n?10:32);
}

CF741D

题目描述:

在这里插入图片描述
n ≤ 5 ∗ 1 0 5 n\le5*10^5 n5105洛谷链接

题目分析:

把字符串压成二进制,回文条件相当于异或之后二进制1的个数<=1.

要求最长路径,考虑合并的时候需要遍历其中一棵子树然后查表。这个应该只能DSU on Tree做。

m x [ S ] mx[S] mx[S]表示到根路径异或状态为 S S S的最大深度。计算 u u u的答案的时候需要枚举轻儿子子树的一个状态 T T T,然后查询 m x [ T ] mx[T] mx[T] m x [ T   x o r   1 < < i ] mx[T~xor~1<<i] mx[T xor 1<<i]。这是两条链合并,然后需要查子树的一条链以及儿子子树中的答案,都很简单。

做DSU的时候,为了避免在转移重儿子时修改桶,往往需要将子树的相对信息改为全局信息(比如前缀和和真实深度)的形式。

Code:

#include<bits/stdc++.h>
#define maxn 500005
#define ADJ(v,u) for(int v=fir[u];v;v=nxt[v])
using namespace std;
const int inf = maxn+5;
int n,m,A[maxn],dep[maxn],siz[maxn],son[maxn],ans[maxn];
char a[maxn];
int fir[maxn],nxt[maxn];
void line(int x,int y){nxt[y]=fir[x],fir[x]=y;}
void dfs1(int u,int ff){
	siz[u]=1,dep[u]=dep[ff]+1;
	ADJ(v,u) A[v]=A[u]^1<<(a[v]-'a'),dfs1(v,u),siz[u]+=siz[v],siz[v]>siz[son[u]]&&(son[u]=v);
}
int mx[1<<22];
void chkmax(int &a,int b){a<b?a=b:0;}
void add(int i,int t){
	if(t>0) chkmax(mx[A[i]],dep[i]);
	else mx[A[i]]=-inf;
}
void Add(int u,int t){add(u,t); ADJ(v,u) Add(v,t);}
void calc(int u,int rt){
	chkmax(ans[rt],dep[u]+mx[A[u]]-2*dep[rt]);
	for(int i=0;i<22;i++) chkmax(ans[rt],dep[u]+mx[A[u]^1<<i]-2*dep[rt]);
	ADJ(v,u) calc(v,rt);
}
void dfs2(int u){
	ADJ(v,u) if(v!=son[u]) dfs2(v),chkmax(ans[u],ans[v]),Add(v,-1);
	if(son[u]) dfs2(son[u]),chkmax(ans[u],ans[son[u]]);
	ADJ(v,u) if(v!=son[u]) calc(v,u),Add(v,1);
	add(u,1);
	chkmax(ans[u],mx[A[u]]-dep[u]);
	for(int i=0;i<22;i++) chkmax(ans[u],mx[A[u]^1<<i]-dep[u]);
}
int main()
{
	memset(mx,-0x3f,sizeof mx);
	scanf("%d",&n);
	for(int i=2,x;i<=n;i++) scanf("%d %c",&x,&a[i]),line(x,i);
	dfs1(1,0),dfs2(1);
	for(int i=1;i<=n;i++) printf("%d%c",ans[i],i==n?10:32);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值