BZOJ-2008 弹飞绵羊(LCT)

来源:互联网 发布:歌词有傻瓜的网络歌曲 编辑:程序博客网 时间:2022/05/28 05:54

2002: [Hnoi2010]Bounce 弹飞绵羊

Time Limit: 10 Sec  Memory Limit: 259 MB
Submit: 11350  Solved: 5769
[Submit][Status][Discuss]

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

LCT模板题,把n+1当做公共父节点,每次求左子树大小即可

#include<cstdio>#include<string.h>#include<queue>#include<algorithm>using namespace std;const int MX = 2e5 + 5;const int inf = 0x3f3f3f3f;int n, m;struct LCT {    int fa[MX], ch[MX][2], rev[MX], sz[MX];    void init() {        for (int i = 0; i <= n + 1; i++) {            ch[i][0] = ch[i][1] = rev[i] = fa[i] = 0;            sz[i] = 1;        }        sz[0] = 0;    }    inline bool check_root(int x) {        return ch[fa[x]][0] != x && ch[fa[x]][1] != x;    }    inline int check_same(int x) {        return x == ch[fa[x]][1];    }    inline void up_rev(int x) {        rev[x] ^= 1;        swap(ch[x][0], ch[x][1]);    }    void pushup(int x) {        sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1;    }    void pushdown(int x) {        if (rev[x]) {            if (ch[x][0]) up_rev(ch[x][0]);            if (ch[x][1]) up_rev(ch[x][1]);            rev[x] = 0;        }    }    void P(int x) {        if (!check_root(x)) P(fa[x]);        pushdown(x);    }    void rotate(int x) {        int y = fa[x], z = fa[y], kind = ch[y][1] == x;        if (!check_root(y)) ch[z][ch[z][1] == y] = x;        fa[x] = z; fa[y] = x; fa[ch[x][!kind]] = y;        ch[y][kind] = ch[x][!kind]; ch[x][!kind] = y;        pushup(y);    }    void splay(int x) {        P(x);        int y, z;        while (!check_root(x)) {            y = fa[x]; z = fa[y];            if (!check_root(y)) {                if (check_same(x) == check_same(y)) rotate(y);                else rotate(x);            }            rotate(x);        }        pushup(x);    }    void access(int x) {        int y = 0;        while (x) {            splay(x);            ch[x][1] = y;            pushup(x);            x = fa[y = x];        }    }    void make_root(int x) {  //将x作为根节点        access(x); splay(x); up_rev(x);    }    void link(int x, int y) {        make_root(x); fa[x] = y; access(x);    }    void cut(int x, int y) {        make_root(x); access(y); splay(y);        ch[y][0] = fa[x] = 0;    }    int find(int x) {  //找根节点        access(x); splay(x);        while (ch[x][0]) x = ch[x][0];        return x;    }    void print(int x) {        if (ch[x][0])print(ch[x][0]);        printf("[%d]", x);        if (ch[x][1])print(ch[x][1]);    }    int query(int x) {        make_root(n + 1);        access(x);        splay(x);        //print(x);printf("\n");        return sz[ch[x][0]];    }} T;int a[MX];int main() {    freopen("in.txt", "r", stdin);    while (~scanf("%d", &n)) {        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);        T.init();        for (int i = 1; i <= n; i++) {            a[i] = min(n + 1, a[i] + i);            T.link(i, a[i]);        }        scanf("%d", &m);        for (int i = 1, op, u, k; i <= m; i++) {            scanf("%d%d", &op, &u); u++;            if (op == 1) printf("%d\n", T.query(u));            else {                scanf("%d", &k);                T.cut(u, a[u]);                T.link(u, a[u] = min(n + 1, u + k));            }        }    }    return 0;}




原创粉丝点击