1. 程式人生 > >[HNOI2010]彈飛綿羊——[LCT]

[HNOI2010]彈飛綿羊——[LCT]

【題目描述】 某天,LostmonkeyLostmonkey發明了一種超級彈力裝置,為了在他的綿羊朋友面前顯擺,他邀請小綿羊一起玩個遊戲。遊戲一開始,LostmonkeyLostmonkey在地上沿著一條直線擺上nn個裝置,每個裝置設定初始彈力系數kiki,當綿羊達到第ii個裝置時,它會往後彈kiki步,達到第i+kii+ki個裝置,若不存在第i+kii+ki個裝置,則綿羊被彈飛。綿羊想知道當它從第ii個裝置起步時,被彈幾次後會被彈飛。為了使得遊戲更有趣,LostmonkeyLostmonkey可以修改某個彈力裝置的彈力系數,任何時候彈力系數均為正整數。

【輸入格式】 第一行包含一個整數nn,表示地上有nn個裝置,裝置的編號從00n1n-1。 接下來一行有nn個正整數,依次為那nn個裝置的初始彈力系數。

第三行有一個正整數mm

接下來mm行每行至少有兩個數iijj,若i=1i=1,你要輸出從jj出發被彈幾次後被彈飛,若i=2i=2則還會再輸入一個正整數kk,表示第jj個彈力裝置的係數被修改成k。

【輸出格式】 對於每個i=1i=1的情況,你都要輸出一個需要的步數,佔一行。

Sample  InputSample\;Input

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

Sample  OutputSample\;Output

2 3

【題意分析】

一個坑點:編號從0到n-1

題目保證每隻綿羊只會往後彈,彈到後面沒有了就直接彈飛。那麼對於被彈飛,可以理解成彈到了第n+1n+1個點。(虛構的一個節點)

輸入的時候,設第xx個點設定成往後彈a[x]a[x],那麼如果x+a[x]>nx+a[x] > nlink(x,x+a[x])link~(x,x+a[x]),否則link(x,n+1)link~(x,n+1)

nk(x,n+1)(被彈飛)

操作的時候,如果是修改,先判斷要修改的點連的是n+1n+1還是x+a[x]x+a[x],先cutcut,然後跟輸入時差不多,判斷之後再linklink。別忘了修改勁度係數!!(此處WA*1) 如果是詢問,那就access(n+1)access~(n+1)splay(n+1)splay~(n+1),然後輸出size[n+1]1size[n+1]-1

Code:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cctype>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#define MAXN 500000
using namespace std;

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

namespace LCT{
    
    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 LCT;

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;
}