[HNOI2010]弹飞绵羊——[LCT]

【题目描述】
某天, L o s t m o n k e y Lostmonkey Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始, L o s t m o n k e y Lostmonkey Lostmonkey在地上沿着一条直线摆上 n n n个装置,每个装置设定初始弹力系数 k i ki ki,当绵羊达到第 i i i个装置时,它会往后弹 k i ki ki步,达到第 i + k i i+ki i+ki个装置,若不存在第 i + k i i+ki i+ki个装置,则绵羊被弹飞。绵羊想知道当它从第 i i i个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣, L o s t m o n k e y Lostmonkey Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。

【输入格式】
第一行包含一个整数 n n n,表示地上有 n n n个装置,装置的编号从 0 0 0 n − 1 n-1 n1
接下来一行有 n n n个正整数,依次为那 n n n个装置的初始弹力系数。

第三行有一个正整数 m m m

接下来 m m m行每行至少有两个数 i i i j j j,若 i = 1 i=1 i=1,你要输出从 j j j出发被弹几次后被弹飞,若 i = 2 i=2 i=2则还会再输入一个正整数 k k k,表示第 j j j个弹力装置的系数被修改成k。

【输出格式】
对于每个 i = 1 i=1 i=1的情况,你都要输出一个需要的步数,占一行。

S a m p l e    I n p u t Sample\;Input SampleInput

4
1 2 1 1
3
1 1
2 1 1
1 1

S a m p l e    O u t p u t Sample\;Output SampleOutput

2
3

【题意分析】

一个坑点:编号从0到n-1

题目保证每只绵羊只会往后弹,弹到后面没有了就直接弹飞。那么对于被弹飞,可以理解成弹到了第 n + 1 n+1 n+1个点。(虚构的一个节点)

输入的时候,设第 x x x个点设置成往后弹 a [ x ] a[x] a[x],那么如果 x + a [ x ] > n x+a[x] > n x+a[x]>n l i n k   ( x , x + a [ x ] ) link~(x,x+a[x]) link (x,x+a[x]),否则 l i n k   ( x , n + 1 ) link~(x,n+1) link (x,n+1)(被弹飞)

操作的时候,如果是修改,先判断要修改的点连的是 n + 1 n+1 n+1还是 x + a [ x ] x+a[x] x+a[x],先 c u t cut cut,然后跟输入时差不多,判断之后再 l i n k link link。别忘了修改劲度系数!!(此处WA*1)
如果是询问,那就 a c c e s s   ( n + 1 ) access~(n+1) access (n+1) s p l a y   ( n + 1 ) splay~(n+1) splay (n+1),然后输出 s i z e [ n + 1 ] − 1 size[n+1]-1 size[n+1]1

Code:

#include
#include
#include
#include
#include
#include
#include
#include
#define MAXN 500000
using namespace std;

int son[MAXN][2],father[MAXN],size[MAXN],lazy[MAXN];
int a[MAXN],stack[MAXN],n,q;

namespace Link_Cut_Tree{
    
    inline bool isroot (int x){
        return !(son[father[x]][0] == x || son[father[x]][1] == x);
    }//是否为根
    
    inline void pushup (int x){
        size[x] = 1;
        if (son[x][0])size[x] += size[son[x][0]];
        if (son[x][1])size[x] += size[son[x][1]];
    }//更新size
    
    inline void pushdown (int x){
        if (lazy[x]){
            swap (son[x][0],son[x][1]);
            if (son[x][0])lazy[son[x][0]] ^= 1;
            if (son[x][1])lazy[son[x][1]] ^= 1;
            lazy[x] = 0;
        }
    }
    
    inline void rotate (int x){
        int y = father[x],z = father[y];
        int k = son[y][1] == x,kk = son[z][1] == y;
        if (!isroot (y))son[z][kk] = x;
        father[x] = z;
        son[y][k] = son[x][k^1];
        father[son[x][k^1]] = y;
        son[x][k^1] = y;
        father[y] = x;
        pushup (y); pushup (x);
    }
    
    inline void splay (int x){
        int top = 0;
        stack[++top] = x;
        for (register int i = x;!isroot (i);i = father[i])
            stack[++top] = father[i];
        for (register int i = top;i;i--)
            pushdown (stack[i]);
        while (!isroot (x)){
            int y = father[x],z = father[y];
            if (!isroot (y))
                (son[y][1] == x) ^ (son[z][1] == y)
                    ? rotate (x) : rotate (y);
            rotate (x);
        }
        pushup (x);
    }
    
    inline void access (int x){
        for (register int y = 0;x;y = x,x = father[x]){
            splay (x);
            son[x][1] = y;
            pushup (x);
        }
    }
    
    inline int findroot (int x){
        access (x);
        splay (x);
        while (son[x][0]){
            pushdown (son[x][0]);
            x = son[x][0];
        }
        return x;
    }
    
    inline void makeroot (int x){
        access (x);
        splay (x);
        lazy[x] ^= 1;
    }
    
    inline void link (int x,int y){
        makeroot (x);
        father[x] = y;
    }
    
    inline void cut (int x,int y){
        makeroot (x);
        access (y);
        splay (y);
        son[y][0] = father[x] = 0;
        pushup (y);
    }
    
    inline int query (int x,int y){
        makeroot (x);
        access (y);
        splay (y);
        return size[y] - 1; 
    }
    
}using namespace Link_Cut_Tree;

int main (){
    scanf ("%d",&n);
    for (register int i = 1;i <= n+1;i++)
        size[i] = 1;
    for (register int i = 1;i <= n;i++){
        int x;
        scanf ("%d",&x);
        (i+x <= n)
            ? link (i,i+x) : link (i,n+1);
        a[i] = x;
    }
    scanf ("%d",&q);
    while (q--){
        int type;
        scanf ("%d",&type);
        if (type == 1){
            int x;
            scanf ("%d",&x); x++;
            printf ("%d\n",query (x,n+1));
        }
        if (type == 2){
            int x,y;
            scanf ("%d%d",&x,&y); x++;
            (x+a[x] <= n)
                ? cut (x,x+a[x]) : cut (x,n+1);
            (x+y <= n)
                ? link (x,x+y) : link (x,n+1);
            a[x] = y;
        }
    }
    return 0;
}

你可能感兴趣的:(平衡树,Splay,LCT,构造)