CodeForces 379F 树的直径

.......

考虑树的直径有两个点,,,,,不用每次都O(n)的去遍历.....

直接求出当前加入的点与直径两点的距离,然后判断一下就好了

....不知道这个小技巧的话,还挺难想的

#include<bits/stdc++.h>
#define MAXN 1000005
using namespace std;

int q,tot,p=0;
int h[MAXN],z[MAXN],f[30][MAXN],dep[MAXN],jl[MAXN],lx=2,mx=4,maxl=2;

struct node{
    int from,to,next;
}e[MAXN<<1];

void init(){
    memset(h,-1,sizeof(h));
    memset(f,0,sizeof(f));
    tot=0;
    p=4;    
}

void add(int x,int y){
    tot++;
    e[tot].from=x;
    e[tot].to=y;
    e[tot].next=h[x];
    h[x]=tot;
}

int dfs(int now,int fa){
    dep[now]=dep[fa]+1;
    for(int i=h[now];i!=(-1);i=e[i].next){
        if(e[i].to!=fa){
            f[0][e[i].to]=now;
            dfs(e[i].to,now);
        }
    }
}

int lca(int x,int y){
    if(dep[x]<dep[y])swap(x,y);
    int dx=dep[x]-dep[y];
    for(int i=0;i<=22;i++){
        if((1<<i)&dx){
            x=f[i][x];
        }
    }
    if(x==y)return x;
    for(int i=22;i>=0;i--){
        if(f[i][x]!=f[i][y]){
            x=f[i][x];
            y=f[i][y];
        }
    }
    return f[0][x];
}

int dis(int x,int y){
    return dep[x]+dep[y]-2*dep[lca(x,y)];
}

int main(){
     cin>>q;init();
     add(1,2),add(2,1);
     add(1,3),add(3,1);
     add(1,4),add(4,1);
     for(int i=1;i<=q;i++){
         //cin>>jl[i];
         scanf("%d",&jl[i]);
         z[jl[i]]=p;
        add(jl[i],p+1),add(p+1,jl[i]);
         add(jl[i],p+2),add(p+2,jl[i]);
         p+=2;
    }
    dfs(1,1);
    for(int i=1;i<=22;i++){
        for(int j=1;j<=p;j++){
            f[i][j]=f[i-1][f[i-1][j]];
        }
    }
    for(int i=1;i<=q;i++){
        int px=z[jl[i]]+1;
        int x=dis(px,lx),y=dis(px,mx);
        if(x>y){
            if(x>maxl){
                mx=px;
                maxl=x;
            }
        }
        else{
            if(y>maxl){
                lx=px;
                maxl=y;
            }
        }
        cout<<maxl<<endl;
    }
}
View Code

猜你喜欢

转载自www.cnblogs.com/shatianming/p/12318813.html
今日推荐