1. 程式人生 > >bzoj4928: 第二題

bzoj4928: 第二題

距離 desc printf long b+ ans 一個點 content tdi

Description

對於一棵有根樹,定義一個點u的k-子樹為u的子樹中距離u不超過k的部分。 註意,假如u的子樹中不存在距離u為k的點,則u的k-子樹是不存在的。 定義兩棵子樹是相同的,當且僅當不考慮點的標號時,他們的形態是 相同的(兒子的順序也需要考慮)。給定一棵n個點,點的標號在[1,n], 以1為根的有根樹。問最大的k,使得存在兩個點u !=v,滿足u的k-子樹與v的k-子樹相同。

Input

第一行輸入一個正整數n。 接下來讀入n個部分,第i個部分描述點i的兒子,且以順序給出。 每個部分首先讀入一個整數x,代表兒子個數。 接下來x個整數,代表從左到右兒子的標號
n ≤ 100000,保證給出的樹是合法的

Output

輸出一個整數k,代表最大的合法的k 已知每個點的a-子樹和b-子樹的hash,可以推出每個點的(a+b)-子樹的hash 對答案倍增,hash判定
#include<cstdio>
#include<cstring>
#define Fe(i,l,r) for(int i=l;i<=r;++i)
typedef unsigned long long u64;
const int N=100007,P=293999;
void maxs(int&a,int b){if(a<b)a=b;}
u64 H(u64 x){
return (x^x>>17^x<<43)+777;} char buf[70007],*ptr=buf+70000; int G(){ if(ptr-buf==70000)fread(ptr=buf,1,70000,stdin); return *ptr++; } int _(){ int x=0; if(ptr-buf<69900){ while(*ptr<48)++ptr; while(*ptr>47)x=x*10+*ptr++-48; }else{ int c=G();
while(c<48)c=G(); while(c>47)x=x*10+c-48,c=G(); } return x; } int n,ans=1; int mem[N],*mp=mem,*e[N],ep[N],fa[20][N],fas[N],id[N],_fa[N],_son[N]; int q[N],ql=0,qr=0,dep[N],md[N]; u64 h[20][N],h2[N],_h[N]; u64 hx[P]; int ht[P],tk=1; bool ins(u64 x){ int w=(unsigned(x)^unsigned(x>>32))%P; while(ht[w]==tk){ if(hx[w]==x)return 1; if((w+=1237)>=P)w-=P; } hx[w]=x;ht[w]=tk; return 0; } template<class T> void cpy(T*a,T*b){memcpy(a+1,b+1,sizeof(T)*n);} void getson(){ memset(_son+1,0,sizeof(int)*n); Fe(t,1,qr){ int w=q[t],f=fas[w]; if(!_son[f])_son[f]=t; } } void cal(int _i){ cpy(_h,h[_i]); cpy(_fa,fa[_i]); for(int i=_i-1;i>=0;--i){ ++tk; cpy(h2,_h); getson(); Fe(t,1,qr){ int w=q[t],f=_fa[w]; if(f)h2[f]=h2[f]*1844677+h[i][w]+(id[fa[0][w]]-_son[f]); } bool is=0; int mn=ans+(1<<i); Fe(w,1,n)if(md[w]+1>=mn&&ins(h2[w])){ is=1; break; } if(is){ ans=mn; Fe(w,1,n){ _h[w]=H(h2[w]); _fa[w]=fa[i][_fa[w]]; fas[w]=fa[i][fas[w]]; } } } } void cal(){ Fe(w,1,n)h[0][w]=20120123103141; for(int i=0;i<19;++i){ ++tk; cpy(h2,h[i]); getson(); Fe(t,1,qr){ int w=q[t],f=fa[i][w]; if(f)h2[f]=h2[f]*1844677+h[i][w]+(id[fa[0][w]]-_son[f]); } bool is=0; int mn=ans+(1<<i); Fe(w,1,n)if(md[w]+1>=mn&&ins(h2[w])){ is=1; break; } if(is){ ans=mn; Fe(w,1,n){ h[i+1][w]=H(h2[w]); fa[i+1][w]=fa[i][fa[i][w]]; fas[w]=fa[i][fas[w]]; } }else return cal(i); } } int main(){ n=_(); for(int i=1;i<=n;++i){ fas[i]=i; e[i]=mp; mp+=ep[i]=_(); for(int j=0;j<ep[i];++j)fa[0][e[i][j]=_()]=i; } for(q[++qr]=1;fa[0][q[1]];++q[1]); while(ql!=qr){ int w=q[++ql]; id[w]=ql; for(int*l=e[w],*r=l+ep[w];l!=r;++l)dep[q[++qr]=*l]=dep[w]+1; } for(int i=qr;i;--i){ int w=q[i]; maxs(md[fa[0][w]],md[w]+1); } cal(); printf("%d\n",ans-1); return 0; }

bzoj4928: 第二題