解题报告 『[HNOI2010]弹飞绵羊(LCT)』

原题地址

LCT的裸题,如果u能到v就link(u, v),如果会被弹飞就link(u, n + 1);

第二个操作先cut再link然后赋值就行了。

 

代码实现如下:

#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (register int i = (a); i <= (b); i++)

const int maxn = 2e5 + 5;

int n, m;
int fa[maxn], rev[maxn], val[maxn], size[maxn], ch[maxn][3];

int get(int x) {return x == ch[fa[x]][1];}

int is_root(int x) {return x ^ ch[fa[x]][0] && x ^ ch[fa[x]][1];}

int read() {
    int x = 0, flag = 0;
    char ch = ' ';
    while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    if (ch == '-') {
        flag = 1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = (x << 1) + (x << 3) + (ch ^ '0');
        ch = getchar();
    }
    return flag ? -x : x;
}

void push_down(int x) {
    if (rev[x]) {
        ch[x][0] ^= ch[x][1] ^= ch[x][0] ^= ch[x][1];
        rev[ch[x][0]] ^= 1;
        rev[ch[x][1]] ^= 1;
        rev[x] = 0;
    }
}

void maintain(int x) {
    size[0] = 0;
    size[x] = size[ch[x][0]] + size[ch[x][1]] + 1;
}

void update(int x) {
    if (!is_root(x)) update(fa[x]);
    push_down(x);
}

void rotate(int x) {
    int y = fa[x], z = fa[y], chx = get(x), chy = get(y);
    if (!is_root(y)) ch[z][chy] = x;
    ch[y][chx] = ch[x][chx ^ 1];
    fa[ch[x][chx ^ 1]] = y;
    ch[x][chx ^ 1] = y;
    fa[y] = x;
    fa[x] = z;
    maintain(y);
    maintain(x);
    maintain(z);
}

void splay(int x) {
    update(x);
    for (register int f = fa[x]; f = fa[x], !is_root(x); rotate(x))
        if (!is_root(f)) rotate(get(x) == get(f) ? f : x);
}

void access(int x) {
    for (register int p = 0; x; p = x, x = fa[x]) {
        splay(x);
        ch[x][1] = p;
        maintain(x);
    }
}

int find(int x) {
    access(x);
    splay(x);
    while (ch[x][0]) {
        push_down(x);
        x = ch[x][0];
    }
    return x;
}

void make_root(int x) {
    access(x);
    splay(x);
    rev[x] ^= 1;
    push_down(x);
}

void split(int u, int v) {
    make_root(u);
    access(v);
    splay(v);
}

void link(int u, int v) {
    make_root(u);
    if (u ^ find(v)) fa[u] = v;
    else return;
}

void cut(int u, int v) {
    split(u, v);
    if (ch[v][0] == u && !ch[u][1])
        fa[u] = ch[v][0] = 0;
    else return;
}

void write(int x) {
    if (x < 0) {
        putchar('-');
        x = -x;
    }
    if (x > 9) write(x / 10);
    putchar(x % 10 + '0');
}

int main() {
    n = read();
    rep(i, 1, n) {
        val[i] = read();
        link(i, i + val[i] <= n ? i + val[i] : n + 1);
    }
    m = read();
    rep(i, 1, m) {
        int j, opt;
        opt = read(), j = read() + 1;
        switch(opt) {
            case(1): {
                split(j, n + 1);
                write(size[n + 1] - 1);
                printf("\n");
                break;
            }
            case(2): {
                int k;
                k = read();
                cut(j, j + val[j] <= n ? j + val[j] : n + 1);
                link(j, j + k <= n ? j + k : n + 1);
                val[j] = k;
                break;
            }
        }
    }
    return 0;
}
View Code
posted @ 2019-08-22 15:18  雲裏霧裏沙  阅读(180)  评论(0编辑  收藏  举报