【樹雜湊】CF763D Timofey and a flat tree
阿新 • • 發佈:2018-11-28
【題目】
原題地址
給定一棵樹,求以哪個點為根時不同構的子樹最多。
【解題思路】
顯然不同的子樹最多有
種,於是我們先維護出以
為根的所有子樹雜湊值,然後再
一遍亂搞即可。
這裡的樹雜湊可以選擇給每一種樹分配一個 並隨機一個權值,一棵樹的雜湊值可以是它所有子樹的權值和,這樣處理換根時可以十分方便。
如果採用傳統的給子樹排序後再計算雜湊值也可以,只是在第二次 的時候需要用 的冪來進行計算,比較麻煩。
【參考程式碼】
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int N=2e5+10;
int n,tot,ans,mx,cnt,dif;
int head[N],num[N];
ull val[N],f[N];
map<ull,int>mp;
int read()
{
int ret=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return ret;
}
struct Tway{int v,nex;}e[N];
void add(int u,int v)
{
e[++tot]=(Tway){v,head[u]};head[u]=tot;
e[++tot]=(Tway){u,head[v]};head[v]=tot;
}
void ins(int x){if(!num[x])++dif;++num[x];}
void del(int x){--num[x];if(!num[x])--dif;}
int get(int x){return mp.count(x)?mp[x]:mp[x]=++cnt;}
void dfs1(int x,int fa)
{
ull sum=0;
for(int i=head[x];i;i=e[i].nex)
if(e[i].v^fa) dfs1(e[i].v,x),sum+=val[f[e[i].v]];
f[x]=get(sum);ins(f[x]);
}
void dfs2(int x,int fa,int c)
{
del(f[x]);
if(dif+1>mx) mx=dif+1,ans=x;
ull sum=0;
for(int i=head[x];i;i=e[i].nex)
if(e[i].v^fa) sum+=val[f[e[i].v]];
sum+=val[c];
for(int i=head[x];i;i=e[i].nex)
{
int v=e[i].v;
if(v==fa) continue;
ull snow=sum-val[f[v]];
ins(get(snow));dfs2(v,x,get(snow));del(get(snow));
}
ins(f[x]);
}
ull rnd(){return (ull)(rand()+1)*2333+(ull)(rand()+1)*19260817+(ull)((rand()+1231)<<28);}
int main()
{
#ifndef ONLINE_JUDGE
freopen("CF763D.in","r",stdin);
freopen("CF763D.out","w",stdout);
#endif
n=read();
for(int i=1;i<=n*2;++i) val[i]=rnd();
for(int i=1;i<n;++i) add(read(),read());
dfs1(1,0);dfs2(1,0,0);
printf("%d\n",ans);
return 0;
}
【總結】
學到了一種新的樹雜湊處理方式qwq