【bzoj2002】弹飞绵羊

Lct裸题

给出一棵树,有修改及询问,修改操作为修改一个节点的父亲,询问一个节点到根的点数。

询问及修改前只需Access一遍即可。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#define Rep(i, x, y) for (int i = x; i <= y; i ++)
#define RepE(i, x) for (int i = pos[x]; i; i = g[i].nex)
#define lc t[x].ch[0]
#define rc t[x].ch[1]
#define Lc t[lc]
#define Rc t[rc]
#define tp t[x].par
#define Tp t[t[x].par]
using namespace std;
typedef long long LL;
const int N = 200005;
struct arr { int ch[2], par, sz; } t[N];
bool rt[N];
int n, m, q;
void Upd(int x) { t[x].sz = Lc.sz + Rc.sz + 1; }
void Sc(int x, int y, bool f) { t[y].ch[f] = x, tp = y; }
void Rot(int x, bool f) {
    int y = tp;
    Sc(t[x].ch[f], y, !f);
    tp = Tp.par; Sc(y, x, f);
    if (rt[y]) rt[y] = 0, rt[x] = 1;
    else Tp.ch[Tp.ch[1] == y] = x;
    Upd(y);
}
void Splay(int x) {
    while (!rt[x]) {
        if (rt[tp]) { Rot(x, Tp.ch[0] == x); break; }
        bool f = (t[Tp.par].ch[1] == tp);
        if (Tp.ch[f] == x) Rot(tp, !f), Rot(x, !f);
        else Rot(x, f), Rot(x, !f); 
    } Upd(x);
}
void Access(int x) {
    Splay(x);
    rt[rc] = 1, rc = 0;
    while (tp) { //cout << 1;
        int y = tp;
        Splay(y);
        rt[t[y].ch[1]] = 1;
        t[y].ch[1] = x;
        rt[x] = 0;
        x = tp, Upd(x);
    }
}
int main()
{
    cin >> n;
    Rep(i, 1, n) {
        int x;
        scanf ("%d", &x), x = min(x+i, n+1);
        t[i].par = x, rt[i] = 1, t[x].sz = 1;
    }
    rt[n+1] = 1, t[n+1].sz = 1;
    cin >> q;
    Rep(i, 1, q) {
        int type, x;
        scanf ("%d%d", &type, &x), x ++;
        if (type == 1) {
            Access(x); Splay(x);
            printf ("%d\n", t[x].sz - 1);
        } else {
            int y;
            scanf ("%d", &y), y = min(x+y, n+1);
            Access(x); Splay(x);
            rt[lc] = 1, Lc.par = tp, lc = 0;
            t[x].sz = Rc.sz + 1, tp = y;
        }
    }
 
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值