1. 程式人生 > >cf379F New Year Tree (樹的直徑+倍增lca)

cf379F New Year Tree (樹的直徑+倍增lca)

可以證明,如果合併兩棵樹,新的直徑的端點一定是原來兩樹中直徑的端點

可以把新加兩個點的操作看成是把兩個只有一個點的樹合併到原來的樹上,然後用其中的一個點去和原來樹上的直徑兩端點更新直徑就可以了

 1 #include<bits/stdc++.h>
 2 #define pa pair<int,int>
 3 #define CLR(a,x) memset(a,x,sizeof(a))
 4 using namespace std;
 5 typedef long long ll;
 6 const int maxn=5e5+10;
 7 
 8 inline ll rd(){
9 ll x=0;char c=getchar();int neg=1; 10 while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();} 11 while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); 12 return x*neg; 13 } 14 15 int fa[maxn*2][22],dep[maxn*2]; 16 int Q,ra,rb,r; 17 18 inline int getdis(int x,int y){
19 int re=dep[x]+dep[y]; 20 if(dep[x]<dep[y]) swap(x,y); 21 for(int i=log2(dep[x]-dep[y]);i>=0&&dep[x]!=dep[y];i--){ 22 if(fa[x][i]&&dep[fa[x][i]]>=dep[y]) 23 x=fa[x][i]; 24 } 25 int lca; 26 if(x==y) lca=x; 27 else{ 28 for
(int i=log2(dep[x]);i>=0;i--){ 29 if(fa[x][i]!=fa[y][i]) 30 x=fa[x][i],y=fa[y][i]; 31 } 32 lca=fa[x][0]; 33 } 34 return re-dep[lca]*2; 35 } 36 37 int main(){ 38 //freopen("","r",stdin); 39 int i,j,k; 40 Q=rd(); 41 fa[2][0]=fa[3][0]=fa[4][0]=1; 42 dep[2]=dep[3]=dep[4]=2;dep[1]=1; 43 ra=2,rb=4;r=2; 44 for(i=1,j=4;i<=Q;i++){ 45 int x=++j,y=++j; 46 fa[x][0]=fa[y][0]=rd(); 47 dep[x]=dep[y]=dep[fa[x][0]]+1; 48 for(k=0;fa[x][k]&&fa[fa[x][k]][k];k++) 49 fa[x][k+1]=fa[y][k+1]=fa[fa[x][k]][k]; 50 int r1=getdis(ra,x),r2=getdis(rb,x); 51 if(r1>r&&r1>=r2){ 52 r=r1,rb=x; 53 }else if(r2>r){ 54 r=r2,ra=x; 55 } 56 printf("%d\n",r); 57 } 58 return 0; 59 }