Bzoj4573: [Zjoi2016]大森林

题面

传送门

Sol

我太菜了,有点思维的题根本不会

sto HJT s t o   H J T

考虑一个 1 1 操作,相当于是l1 l l 处长节点的位置不同了
那么在l1处长,然后接在 l l 就好了
r r+1 r + 1 同理

考虑怎么来做
虚点的思想
维护一个全局的树,上面有虚点和实点
每次 0 0 操作直接长实点link
1 1 操作就新建虚点,接在原来的虚点上
这样利用上面的思想
对于1操作,只要在 l1 l − 1 处,把当前生长节点的整个子树接在 l l x
然后再在 r r r+1时接回来就能表示出每棵树了

那么把操作 1 1 拆成两个,l r+1 r + 1
按端点 sort s o r t 就能表示了

考虑询问,首先直接把一棵树建完后再查询是没有影响的
那么每次到一棵树,做完所有操作就可以询问了
给每个点赋权值,实点为 1 1 ,虚点为0

LCT L C T u,v u , v lca l c a
Access(u) A c c e s s ( u ) ,然后 Access(y) A c c e s s ( y ) 遇到的最后一条虚边上面的点就是 lca l c a
求路径长度,就是 1 1 u的权值和+ 1 1 v的- 21 2 ∗ 1 lca l c a

HJT orz H J T   o r z

# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;

template <class Int>
IL void Input(RG Int &x){
    RG int z = 1; RG char c = getchar(); x = 0;
    for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    x *= z;
}

const int maxn(3e5 + 5);

int fa[maxn], ch[2][maxn], sum[maxn], val[maxn];

IL int Son(RG int x){
    return ch[1][fa[x]] == x;
}

IL int Isroot(RG int x){
    return ch[0][fa[x]] != x && ch[1][fa[x]] != x;
}

IL void Update(RG int x){
    sum[x] = val[x] + sum[ch[0][x]] + sum[ch[1][x]];
}

IL void Rotate(RG int x){
    RG int y = fa[x], z = fa[y], c = Son(x);
    if(!Isroot(y)) ch[Son(y)][z] = x; fa[x] = z;
    ch[c][y] = ch[!c][x], fa[ch[c][y]] = y;
    ch[!c][x] = y, fa[y] = x;
    Update(y);
}

IL void Splay(RG int x){
    for(RG int y = fa[x]; !Isroot(x); Rotate(x), y = fa[x])
        if(!Isroot(y)) Son(x) ^ Son(y) ? Rotate(x) : Rotate(y);
    Update(x);
}

IL int Access(RG int x){
    RG int y = 0;
    for(; x; y = x, x = fa[x]) Splay(x), ch[1][x] = y, Update(x);
    return y;
}

IL void Cut(RG int x){
    Access(x), Splay(x), ch[0][x] = fa[ch[0][x]] = 0, Update(x);
}

int n, m, id[maxn], num, tot, ql[maxn], qr[maxn], q, ans[maxn], now, cnt;

struct Query{
    int pos, x, y, id;

    IL int operator <(RG Query B) const{
        return pos != B.pos ? pos < B.pos : id < B.id;
    }
} qry[maxn];

int main(RG int argc, RG char* argv[]){
    Input(n), Input(m);
    id[1] = ql[1] = 1, qr[1] = n;
    num = tot = val[1] = 1;
    fa[now = ++tot] = 1;
    for(RG int i = 1, op, l, r, x; i <= m; ++i){
        Input(op), Input(l), Input(r);
        if(op == 1){
            Input(x), l = max(l, ql[x]), r = min(r, qr[x]);
            if(l > r) continue;
            fa[++tot] = now;
            qry[++cnt] = (Query){l, tot, id[x], 0};
            qry[++cnt] = (Query){r + 1, tot, now, 0};
            now = tot;
        }
        else if(op == 0){
            val[++tot] = 1;
            fa[id[++num] = tot] = now;
            ql[num] = l, qr[num] = r;
        }
        else Input(x), qry[++cnt] = (Query){l, id[r], id[x], ++q};
    }
    sort(qry + 1, qry + cnt + 1);
    for(RG int i = 1, lca; i <= cnt; ++i)
        if(qry[i].id){
            Access(qry[i].x), Splay(qry[i].x), ans[qry[i].id] += sum[qry[i].x];
            lca = Access(qry[i].y), Splay(qry[i].y), ans[qry[i].id] += sum[qry[i].y];
            Access(lca), Splay(lca), ans[qry[i].id] -= (sum[lca] << 1);
        }
        else Cut(qry[i].x), fa[qry[i].x] = qry[i].y;
    for(RG int i = 1; i <= q; ++i) printf("%d\n", ans[i]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值