[BZOJ2002][Hnoi2010]Bounce 弹飞绵羊

来源:互联网 发布:基于hadoop的数据挖掘 编辑:程序博客网 时间:2024/05/21 23:32

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