[BZOJ2002][Hnoi2010]Bounce 彈飛綿羊

[Hnoi2010]Bounce 彈飛綿羊

Description

某天,Lostmonkey發明了一種超級彈力裝置,爲了在他的綿羊朋友面前顯擺,他邀請小綿羊一起玩個遊戲。遊戲一開始,Lostmonkey在地上沿着一條直線擺上n個裝置,每個裝置設定初始彈力系數ki,當綿羊達到第i個裝置時,它會往後彈ki步,達到第i+ki個裝置,若不存在第i+ki個裝置,則綿羊被彈飛。綿羊想知道當它從第i個裝置起步時,被彈幾次後會被彈飛。爲了使得遊戲更有趣,Lostmonkey可以修改某個彈力裝置的彈力系數,任何時候彈力系數均爲正整數。
Input
第一行包含一個整數n,表示地上有n個裝置,裝置的編號從0到n-1,接下來一行有n個正整數,依次爲那n個裝置的初始彈力系數。第三行有一個正整數m,接下來m行每行至少有兩個數i、j,若i=1,你要輸出從j出發被彈幾次後被彈飛,若i=2則還會再輸入一個正整數k,表示第j個彈力裝置的係數被修改成k。對於20%的數據n,m<=10000,對於100%的數據n<=200000,m<=100000
Output
對於每個i=1的情況,你都要輸出一個需要的步數,佔一行。
Sample Input
4
1 2 1 1
3
1 1
2 1 1
1 1
Sample Output
2
3

Solution
不同於之前的LCT,這裏要求維護一棵有根樹,所以不能隨便換根,一種方法是不換根link/cut,一種是給所有森林加一個公共根

Code

#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
typedef long long ll;
typedef pair<int, int> PII;
template<typename T> inline void read(T &x){
    x = 0; T f = 1; char ch = getchar();
    while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); }
    while (isdigit(ch))  { x = x * 10 + ch - '0'; ch = getchar(); }
    x *= f;
}

const int N = 200100;
struct Node{
    int sz, rev_tag; Node *c[2], *fa;
    inline int d(){
        if (fa->c[0] != this && fa->c[1] != this) return -1;
        return fa->c[1] == this;
    }
    inline void sc(Node *p, int d) { c[d] = p; p->fa = this; }
    inline void push_up(){ sz = c[0]->sz + c[1]->sz + 1; }
    inline void rev(){ swap(c[0], c[1]); rev_tag ^= 1; }
    void push_down();
}pool[N<<1], *null=pool, *tail=pool+1, *loc[N];
void Node :: push_down(){
    if (this->d() != -1) fa->push_down();
    if (rev_tag){
        rep(i, 0, 1) if (c[i] != null) c[i]->rev();
        rev_tag ^= 1;
    }
}
int n, m, k[N];

inline void setnull(){
    null->c[0] = null->c[1] = null->fa = null; null->sz = null->rev_tag = 0;
}
inline Node *newNode(){
    tail->c[0] = tail->c[1] = tail->fa = null; tail->sz = 1; tail->rev_tag = 0;
    return tail++;
}
void rot(Node *x){
    Node *y = x->fa; int d = x->d();
    if (y->d() == -1) x->fa = y->fa; else y->fa->sc(x, y->d());
    y->sc(x->c[!d], d); y->push_up();
    x->sc(y, !d);
}
void splay(Node *x){
    for (x->push_down(); x->d() != -1; ){
        if (x->fa->d() == -1) rot(x);
        else x->d() == x->fa->d() ?
             (rot(x->fa), rot(x)) : (rot(x), rot(x));
    }
    x->push_up();
}
void access(Node *x){
    for (Node *t = null; x != null; t = x, x = x->fa)
        splay(x), x->c[1] = t, x->push_up();
}
void mkroot(Node *x){ access(x); splay(x); x->rev(); }
void link(Node *x, Node *y){ mkroot(x); x->fa = y; }
void cut(Node *x, Node *y){ mkroot(x); access(y); splay(y); y->c[0] = x->fa = null; y->push_up(); }
int main(){
    setnull();

    read(n);
    rep(i, 1, n+1) loc[i] = newNode();
    rep(i, 1, n){ read(k[i]); link(loc[i], loc[min(i+k[i], n+1)]); }
    read(m);
    for (; m; m--){
        int opt, j, w; read(opt); read(j); j++;
        if (opt == 1){
            mkroot(loc[j]); access(loc[n+1]); splay(loc[n+1]); 
            printf("%d\n", loc[n+1]->sz-1); 
        }else { read(w); 
            cut(loc[j], loc[min(n+1, j+k[j])]);
            link(loc[j], loc[min(n+1, j+(k[j] = w))]);
        }
    }

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章