bzoj2002 弹飞绵羊 lct版

这道题就是维护一个有根的lct 一开始建树全部建虚边 求多少次弹出就是求他到根的距离(根为n+1)

这里有个小技巧 将n+1作为根而没有虚根操作起来会比较方便

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int M=200007;
int read(){
    int ans=0,f=1,c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
    return ans*f;
}
int n,m,c[M][2],size[M],fa[M];
bool isrt(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}
void up(int x){size[x]=size[c[x][0]]+size[c[x][1]]+1;}
void rotate(int x){
    int y=fa[x],z=fa[y],l=0,r=1;
    if(c[y][1]==x) l=1,r=0;
    if(!isrt(y)) c[z][c[z][1]==y]=x;
    fa[y]=x; fa[x]=z; fa[c[x][r]]=y;
    c[y][l]=c[x][r]; c[x][r]=y;
    up(y); up(x);
}
void splay(int x){
    while(!isrt(x)){
        int y=fa[x],z=fa[y];
        if(!isrt(y)){
            if(c[z][0]==y^c[y][0]==x) rotate(x);
            else rotate(y);
        }
        rotate(x);
    }
}
void acs(int x){
    int t=0,y=x;
    while(x){
        splay(x);
        c[x][1]=t;
        up(x);
        t=x; x=fa[x];
    }
    splay(y);
}
void cut_link(int x,int y){
    acs(x);
    fa[c[x][0]]=0; c[x][0]=0;
    fa[x]=min(y+x,n+1);
}
int push_ans(int x){acs(x); return size[x]-1;}
int main()
{
    int x,y;
    n=read();
    for(int i=1;i<=n+1;i++) size[i]=1;
    for(int i=1;i<=n;i++) y=read(),fa[i]=min(i+y,n+1);
    m=read();
    while(m--){
        if(read()==1) x=read()+1,printf("%d\n",push_ans(x));
        else x=read()+1,y=read(),cut_link(x,y);
    }
    return 0;
}
View Code

 

posted @ 2017-06-12 14:20  友人Aqwq  阅读(165)  评论(0编辑  收藏  举报