CF600E
题目描述:
树上每个点有个颜色,记子树内出现次数最多的颜色的出现次数为
c
n
t
cnt
cnt,求子树中出现次数为
c
n
t
cnt
cnt的颜色的编号和。对每个子树都要算。
n
≤
100000
n\le100000
n≤100000
题目分析:
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
n≤5∗105,洛谷链接
题目分析:
把字符串压成二进制,回文条件相当于异或之后二进制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);
}