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
",r);
57     }
58     return 0;
59 }
原文地址:https://www.cnblogs.com/Ressed/p/9811228.html