[HNOI2010] 弹飞绵羊

题目链接:戳我
比较模板的LCT了。。。。
如果是更改操作的话就是先断开它和原先往后弹到的那个边,之后再连上新边。
如果是查询操作就询问它到弹飞点的距离。
那么弹飞点如何处理呢?就是新开一个点(比如说n+1)当某个点如果会被弹飞的话就向它连一条边即可。
注意函数中x,y的先后关系是有影响的。
其他就没有什么了,就是LCT的普通操作啦。
代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAXN 200010
using namespace std;
int n,m,tot,to,op,cur,p;
int s[MAXN];
struct Node{int ch[2],val,ff,rev,son;}t[MAXN];
inline int ls(int x){return t[x].ch[0];}
inline int rs(int x){return t[x].ch[1];}
inline void push_up(int x){t[x].son=t[ls(x)].son+t[rs(x)].son+1;}
inline bool isroot(int x){return (ls(t[x].ff)!=x)&&(rs(t[x].ff)!=x);}
inline void push_down(int x)
{
    if(t[x].rev==0) return;
    t[ls(x)].rev^=1,t[rs(x)].rev^=1;
    swap(t[x].ch[0],t[x].ch[1]);
    t[x].rev^=1;
}
inline void rotate(int x)
{
    int y=t[x].ff;
    int z=t[y].ff;
    int k=t[y].ch[1]==x;
    if(!isroot(y)) t[z].ch[t[z].ch[1]==y]=x; t[x].ff=z;
    t[y].ch[k]=t[x].ch[k^1]; t[t[x].ch[k^1]].ff=y;
    t[x].ch[k^1]=y; t[y].ff=x;
    push_up(y),push_up(x);
}
inline void splay(int x)
{
    s[tot=1]=x;
    for(int i=x;!isroot(i);i=t[i].ff) s[++tot]=t[i].ff;
    while(tot) push_down(s[tot--]);
    while(!isroot(x))
    {
        int y=t[x].ff,z=t[y].ff;
        if(!isroot(y))
            ((t[y].ch[0]==x)^(t[z].ch[0]==y))?rotate(x):rotate(y);
        rotate(x);
    }
}
inline void access(int x)
{   
    for(int y=0;x;y=x,x=t[x].ff)  
        splay(x),t[x].ch[1]=y,push_up(x);
}
inline void makeroot(int x){access(x);splay(x);t[x].rev^=1;}
inline void split(int x,int y){makeroot(x);access(y);splay(y);}
inline void cut(int x,int y){split(x,y);t[y].ch[0]=t[x].ff=0;}
inline void link(int x,int y){makeroot(x);t[x].ff=y;}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d",&n);
    to=n+1;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&t[i].val);
        t[i].son=1;
        if(t[i].val+i>n) link(to,i); 
        else link(i+t[i].val,i);
    }
    t[n+1].son=1;
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&op,&cur);cur++;
        if(op==1)
        {
            split(to,cur);
            printf("%d\n",t[cur].son-1);
        }
        else
        {
            scanf("%d",&p);
            if(t[cur].val+cur>n) cut(to,cur);
            else cut(t[cur].val+cur,cur);
            t[cur].val=p;
            link(cur,min(t[cur].val+cur,to));
        }
    }
}
posted @ 2019-01-17 22:48  风浔凌  阅读(148)  评论(0编辑  收藏  举报