Hnoi2010弹飞绵羊题解LCT

  • 题目大意
    给定一个序列,每个点有一个权值a[i],一只绵羊若站在点i上会被弹到第i+a[i]个点上,支持单点修改操作,求从某个点出发经过多少次会被弹飞。

  • 题解
    令每个点的父亲结点是会被弹到的结点,那询问时每个点的答案就是这个点的深度。
    LCT维护size域即可

  • 一开始以为是有向树,后来发现自己犯2了,按无向的做法就可以。

  • 做这种题千万别手残。我因为一句x->rever()打成x->rev^=1,就有了如下结果,调了快一整天了!
    Hnoi2010弹飞绵羊题解LCT_第1张图片

  • Code

#include 
#include 
#define maxn 200005
using namespace std;
int n, m, val[maxn];
struct node
{
    bool rev;
    int s;
    node *fa, *lc, *rc;
    node() { rev = false; s = 0; fa = lc = rc = NULL; }
    node(bool xrev, int xs, node *xfa, node *xlc, node *xrc)
    {
        rev = xrev; s = xs;
        fa = xfa; lc = xlc; rc = xrc;
    }
    inline void update();
    inline void rever();
    void pushdown();
}*nil = new node(), *T[maxn], *S[maxn];
inline void node :: update()
{
    s = lc -> s + rc -> s + 1;
}
inline void node :: rever()
{
    rev ^= 1;
    swap(lc, rc);
}
void node :: pushdown()
{
    if(rev)
    {
        rev = false;
        lc -> rever();
        rc -> rever();
    }
}
void zig(node *x)
{
    node *y = x -> fa;
    y -> lc = x -> rc;
    x -> rc -> fa = y;
    x -> rc = y;
    x -> fa = y -> fa;
    if(y == y -> fa -> lc) y -> fa -> lc = x;
    else if(y == y -> fa -> rc) y -> fa -> rc = x;
    y -> fa = x;
    y -> update();
}
void zag(node *x)
{
    node *y = x -> fa;
    y -> rc = x -> lc;
    x -> lc -> fa = y;
    x -> lc = y;
    x -> fa = y -> fa;
    if(y == y -> fa -> lc) y -> fa -> lc = x;
    else if(y == y -> fa -> rc) y -> fa -> rc = x;
    y -> fa = x;
    y -> update();
}
void splay(node *x)
{
    int top = 0;
    S[top++] = x;
    for(node *i = x; i == i -> fa -> lc || i == i -> fa -> rc; i = i -> fa)
    {
        S[top++] = i -> fa;
    }
    while(top--) S[top] -> pushdown();
    node *y = nil, *z = nil;
    while(x == x -> fa -> lc || x == x -> fa -> rc)
    {
        y = x -> fa; z = y -> fa;
        if(x == y -> lc)
        {
            if(y == z -> lc) zig(y);
            zig(x);
        }
        else
        {
            if(y == z -> rc) zag(y);
            zag(x);
        }
    }
    x -> update();
}
inline void access(node *x)
{
    for(node *y = nil; x != nil; y = x, x = x -> fa)
    {
        splay(x);
        x -> rc = y;
        x -> update();
    }
}
inline void makeroot(node *x)
{
    access(x); splay(x); x -> rever();
}
inline void lnk(node *x, node *y)
{
    makeroot(x);
    x -> fa = y;
}
inline void cut(node *x, node *y)
{
    makeroot(x);
    access(y); splay(y);
    x -> fa = y -> lc = nil;
    y -> update();
}
inline int query(node *x)
{
    makeroot(T[n]);
    access(x); splay(x);
    return x -> lc -> s;
}
int main()
{
    int opt, a, b;
    scanf("%d", &n);
    *nil = node(false, 0, nil, nil, nil);
    for(int i = 0; i <= n; ++i) T[i] = new node(false, 1, nil, nil, nil);
    for(int i = 0; i < n; ++i)
    {
        scanf("%d", &val[i]);
        T[i] -> fa = T[min(n, i + val[i])];
    }
    scanf("%d", &m);
    while(m--)
    {
        scanf("%d", &opt);
        if(opt == 1)
        {
            scanf("%d", &a);
            printf("%d\n", query(T[a]));
        }
        else
        {
            scanf("%d%d", &a, &b);
            cut(T[a], T[min(n, a + val[a])]);
            val[a] = b;
            lnk(T[a], T[min(n, a + val[a])]);
        }
    }
    for(int i = 0; i < n; ++i)
    {
        delete T[i];
        T[i] = NULL;
    }
    delete nil;
    nil = NULL;
    return 0;
}

你可能感兴趣的:(动态树LCT,OI党坚毅的步伐,树结构)