Bzoj4573: [Zjoi2016]大森林
2018-04-09 21:49
337 查看
题面
传送门Sol
我太菜了,有点思维的题根本不会\(sto \ HJT\)
考虑一个\(1\)操作,相当于是\(l-1\)和\(l\)处长节点的位置不同了
那么在\(l-1\)处长,然后接在\(l\)就好了
\(r\)和\(r+1\)同理
考虑怎么来做
虚点的思想
维护一个全局的树,上面有虚点和实点
每次\(0\)操作直接长实点\(link\)
\(1\)操作就新建虚点,接在原来的虚点上
这样利用上面的思想
对于\(1\)操作,只要在\(l-1\)处,把当前生长节点的整个子树接在\(l\)的\(x\)处
然后再在\(r\)到\(r+1\)时接回来就能表示出每棵树了
那么把操作\(1\)拆成两个,\(l\)和\(r+1\)
按端点\(sort\)就能表示了
考虑询问,首先直接把一棵树建完后再查询是没有影响的
那么每次到一棵树,做完所有操作就可以询问了
给每个点赋权值,实点为\(1\),虚点为\(0\)
\(LCT\)求\(u, v\)的\(lca\)
\(Access(u)\),然后\(Access(y)\)遇到的最后一条虚边上面的点就是\(lca\)
求路径长度,就是\(1\)到\(u\)的权值和+\(1\)到\(v\)的-\(2*1\)到\(lca\)的
\(HJT \ orz\)
# 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; }
相关文章推荐
- [BZOJ4573][UOJ#195][Zjoi2016][LCT][离线]大森林
- bzoj 4573: [Zjoi2016]大森林 lct
- [BZOJ4573][[Zjoi2016]大森林][LCT建虚点]
- [bzoj4573][UOJ#195][ZJOI2016]大森林
- BZOJ4573:[ZJOI2016]大森林——题解
- [BZOJ4573][ZJOI2016]大森林(LCT建虚点)
- BZOJ4573 : [Zjoi2016]大森林
- bzoj 4573: [Zjoi2016]大森林
- [LCT || splay维护括号序列] BZOJ 4573 [Zjoi2016]大森林
- [BZOJ4573][ZJOI2016]大♂森林
- [BZOJ4455][Zjoi2016]小星星(容斥原理+树形DP)
- 【ZJOI2016】大森林
- 洛谷P3348 [ZJOI2016]大森林(LCT,虚点,树上差分)
- bzoj4456 [Zjoi2016]旅行者
- [带有虚点的LCT] BZOJ 4573: 大森林
- bzoj 4455: [Zjoi2016]小星星 树形dp+容斥原理
- bzoj 4455: [Zjoi2016]小星星
- 【BZOJ 4455】【UOJ #185】【ZJOI 2016】小星星
- 【bzoj4455】[Zjoi2016]小星星
- BZOJ4455 ZJOI2016小星星(容斥原理+树形dp)