bzoj 2002 [Hnoi2010]Bounce 弹飞绵羊 LCT

Posted copperoxide

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 2002 [Hnoi2010]Bounce 弹飞绵羊 LCT相关的知识,希望对你有一定的参考价值。

题面

题目传送门

解法

正解是LCT,当然分块也可以做

先简单讲一下分块的做法吧:

分成(sqrt n)个块,每一个元素维护最近的到达不是自己这一块的位置和步数

预处理直接倒着做即可

时间复杂度:(O(msqrt n))

当然,LCT的解法比较优,但是代码较长

显然,每一次跳相当于一条边

可以发现,这些边构成了一棵树

建一个新点(n+1),如果到达这个点,就说明已经被弹出

修改只要维护删边和加边,询问就是求两个点之间的距离

时间复杂度:(O(m log n))

代码

#include <bits/stdc++.h>
#define N 200010
using namespace std;
template <typename node> void chkmax(node &x, node y) {x = max(x, y);}
template <typename node> void chkmin(node &x, node y) {x = min(x, y);}
template <typename node> void read(node &x) {
    x = 0; int f = 1; char c = getchar();
    while (!isdigit(c)) {if (c == ‘-‘) f = -1; c = getchar();}
    while (isdigit(c)) x = x * 10 + c - ‘0‘, c = getchar(); x *= f;
}
struct Node {
    int fa, rev, siz, pathfa, child[2];
} t[N];
int n, k[N];
int son(int x, int y) {return t[x].child[1] == y;}
int siz(int x) {return t[x].siz;}
void rev(int x) {t[x].rev ^= 1;}
void Clear() {
    for (int i = 1; i <= n; i++)
        t[i] = (Node) {0, false, 1, 0, 0, 0};
}
void update(int x) {if (!x) return; t[x].siz = 1 + siz(t[x].child[0]) + siz(t[x].child[1]);}
void Connect(int x, int y, int k) {t[x].child[k] = y, t[y].fa = x; update(x);}
void pushdown(int x) {
    int k = t[x].rev;
    if (k) {
        rev(x), swap(t[x].child[0], t[x].child[1]);
        rev(t[x].child[0]), rev(t[x].child[1]);
    }
}
void Rotate(int x) {
    int y = t[x].fa, z = t[y].fa;
    pushdown(y); pushdown(x);
    swap(t[y].pathfa, t[x].pathfa);
    int a = son(y, x), b = !a;
    Connect(z, x, son(z, y));
    Connect(y, t[x].child[b], a);
    Connect(x, y, b);
    update(y), update(x);
}
void Splay(int x) {
    while (t[x].fa) {
        int y = t[x].fa, z = t[y].fa;
        if (z) {
            pushdown(z), pushdown(y);
            (son(z, y) ^ son(y, x)) ? Rotate(x) : Rotate(y);
        }
        Rotate(x);
    }
}
void expose(int x) {
    Splay(x); pushdown(x);
    int y = t[x].child[1];
    t[y].fa = 0, t[y].pathfa = x;
    t[x].child[1] = 0, update(x);
}
void access(int x) {
    for (expose(x); t[x].pathfa; Splay(x)) {
        expose(t[x].pathfa);
        Connect(t[x].pathfa, x, 1);
        t[x].pathfa = 0;
    }
}
void evert(int x) {access(x); Splay(x); rev(x);}
void link(int x, int y) {evert(y), t[y].pathfa = x;}
void cut(int x, int y) {
    evert(x), access(y);
    Splay(y); pushdown(y);
    t[t[y].child[0]].fa = 0;
    t[y].child[0] = 0; update(y);
}
int dis(int x, int y) {
    evert(x), access(y); Splay(y);
    return t[y].siz - 1;
}
int main() {
    read(n); n++; Clear();
    for (int i = 1; i < n; i++) read(k[i]);
    for (int i = 1; i < n; i++)
        if (i + k[i] >= n) link(i, n);
            else link(i, i + k[i]);
    int q; read(q);
    while (q--) {
        int op; read(op);
        if (op == 1) {
            int x; read(x);
            cout << dis(++x, n) << "
";
        } else {
            int x, y; read(x), read(y); x++;
            cut(x, (x + k[x] >= n) ? n : x + k[x]); k[x] = y;
            link(x, (x + k[x] >= n) ? n : x + k[x]);
        }
    }
    return 0;
}

以上是关于bzoj 2002 [Hnoi2010]Bounce 弹飞绵羊 LCT的主要内容,如果未能解决你的问题,请参考以下文章

bzoj2002HNOI2010Bounce 弹飞绵羊

bzoj 2002: [Hnoi2010]Bounce 弹飞绵羊

BZOJ2002: [Hnoi2010]Bounce 弹飞绵羊

BZOJ2002:[HNOI2010]弹飞绵羊——题解

[BZOJ 2002][Luogu 3203][HNOI2010]Bounce 弹飞绵羊

[bzoj2002][Hnoi2010]Bounce弹飞绵羊_LCT