JZOJ4753【GDOI2017模拟9.4】种树 LCT维护子树信息+换根时维护Dfs序(CC MONOPLOY加强版)
来源:互联网 发布:steam联机游戏mac 编辑:程序博客网 时间:2024/05/24 06:37
题目大意
给定一颗
1.将节点
2.将树根改为节点
3.查询节点
解题思路
我们先考虑一个子问题,假设没有第二个操作,我们应该怎么维护?
如果没有第二个操作,那么树的根是确定的,也就是说树的DFS序是确定的。我们发现对于第一种操作很像
1.对于把虚边改成实边:在
2.对于把实边改成虚边:就是
至于维护区间和,只要以DFS序为下标用线段树维护。(这就是CC MONOPLOY)。
那么我们考虑又换个操作的情况,如果有了换根操作,那么DFS序就会乱,线段树维护的值就会有问题。那么我们考虑不改变DFS序,只是在打
1.
2.
3.
那么每次查询和修改再加以判断一下就可以维护换根操作。
程序
//YxuanwKeith#include <cstring>#include <cstdio>#include <algorithm>using namespace std;const int MAXN = 2e5;typedef long long LL;//struct Tree {int Tag; LL Sum;} Tr[MAXN * 4];int N, Q, cnt, Root, D[MAXN], L[MAXN], R[MAXN], Deep[MAXN], Ord[MAXN], Tag[MAXN * 4], Fa[MAXN][20];int tot, Next[MAXN * 2], Last[MAXN], Go[MAXN * 2], Pre[MAXN], Son[MAXN][2], Rev[MAXN];bool Flag[MAXN];LL Sum[MAXN * 4];void Read(int &Now) { char c; while (c = getchar(), c < '0' || c > '9'); Now = c - 48; while (c = getchar(), c >= '0' && c <= '9') Now = Now * 10 + c - 48;}void Reverse(int u) { if (Rev[u]) { Rev[Son[u][0]] ^= 1, Rev[Son[u][1]] ^= 1; swap(Son[u][0], Son[u][1]); Rev[u] = 0; }}void Link(int u, int v) { Next[++ tot] = Last[u], Last[u] = tot, Go[tot] = v;}void Update(int Now, int l, int r, int Val) { Tag[Now] += Val, Sum[Now] += LL(r - l + 1) * Val; }void Push(int x, int l, int r) { int Mid = (l + r) >> 1; Update(x * 2, l, Mid, Tag[x]), Update(x * 2 + 1, Mid + 1, r, Tag[x]); Tag[x] = 0;} void Modify(int x, int l, int r, int lx, int rx, int Val) { if (lx > rx) return; if (l == lx && r == rx) { Update(x, l, r, Val); return; } Push(x, l, r); int Mid = (l + r) >> 1; if (rx <= Mid) Modify(x * 2, l, Mid, lx, rx, Val); else if (lx > Mid) Modify(x * 2 + 1, Mid + 1, r, lx, rx, Val); else Modify(x * 2, l, Mid, lx, Mid, Val), Modify(x * 2 + 1, Mid + 1, r, Mid + 1, rx, Val); Sum[x] = Sum[x * 2] + Sum[x * 2 + 1];}LL Query(int x, int l, int r, int lx, int rx) { if (lx > rx) return 0; if (l == lx && r == rx) return Sum[x]; Push(x, l, r); int Mid = (l + r) >> 1; if (rx <= Mid) return Query(x * 2, l, Mid, lx, rx); else if (lx > Mid) return Query(x * 2 + 1, Mid + 1, r, lx, rx); else return Query(x * 2, l, Mid, lx, Mid) + Query(x * 2 + 1, Mid + 1, r, Mid + 1, rx);}int Chk(int l, int r) { return max(r - l + 1, 0);}int GetDel(int Now, int Goal) { for (int i = 19; i + 1; i --) if (Deep[Fa[Now][i]] > Deep[Goal]) Now = Fa[Now][i]; return Now;}double Query(int u) { LL Ans = 0; int Num = 0; if (u == Root || L[Root] < L[u] || L[Root] > R[u]) Ans += Query(1, 1, N, L[u], R[u]), Num += Chk(L[u], R[u]); else { Ans += Query(1, 1, N, 1, L[u] - 1), Num += Chk(1, L[u] - 1); Ans += Query(1, 1, N, R[u] + 1, N), Num += Chk(R[u] + 1, N); int Del = GetDel(Root, u); Ans += Query(1, 1, N, L[u], L[Del] - 1), Num += Chk(L[u], L[Del] - 1); Ans += Query(1, 1, N, R[Del] + 1, R[u]), Num += Chk(R[Del] + 1, R[u]); } return 1.0 * Ans / (1.0 * Num);}bool IsRoot(int Now) {return Son[Pre[Now]][0] != Now && Son[Pre[Now]][1] != Now;}void Rotate(int Now) { int Fa = Pre[Now], Gran = Pre[Fa], Side = (Son[Fa][1] == Now); if (!IsRoot(Fa)) Son[Gran][Son[Gran][1] == Fa] = Now; Pre[Now] = Gran, Pre[Fa] = Now; Son[Fa][Side] = Son[Now][!Side], Pre[Son[Fa][Side]] = Fa; Son[Now][!Side] = Fa;}void Splay(int Now) { static int D[MAXN], top; D[top = 1] = Now; for (int p = Now; !IsRoot(p); p = Pre[p]) D[++ top] = Pre[p]; for (; top; top --) Reverse(D[top]); for (; !IsRoot(Now); Rotate(Now)) { int Fa = Pre[Now], Gran = Pre[Fa]; if (IsRoot(Fa)) continue; (Son[Fa][1] == Fa) ^ (Son[Gran][1] == Fa) ? Rotate(Now) : Rotate(Fa); }}int GetSon(int Now) { Reverse(Now); for (; Son[Now][0]; Now = Son[Now][0], Reverse(Now)); return Now;}void Access(int Now) { for (int t = 0; Now; Son[Now][1] = t, t = Now, Now = Pre[Now]) { Splay(Now); if (Son[Now][1]) { int S = GetSon(Son[Now][1]); if (S == Root || L[Root] < L[S] || L[Root] > R[S]) Modify(1, 1, N, L[S], R[S], 1); else { Modify(1, 1, N, 1, L[S] - 1, 1); Modify(1, 1, N, R[S] + 1, N, 1); int Del = GetDel(Root, S); Modify(1, 1, N, L[S], L[Del] - 1, 1); Modify(1, 1, N, R[Del] + 1, R[S], 1); } }; if (t) { int S = GetSon(t); if (S == Root || L[Root] < L[S] || L[Root] > R[S]) Modify(1, 1, N, L[S], R[S], -1); else { Modify(1, 1, N, 1, L[S] - 1, -1); Modify(1, 1, N, R[S] + 1, N, -1); int Del = GetDel(Root, S); Modify(1, 1, N, L[S], L[Del] - 1, -1); Modify(1, 1, N, R[Del] + 1, R[S], -1); } } }}void Build(int x, int l, int r) { if(l == r) { Sum[x] = Deep[Ord[l]] + 1; return; } int Mid = (l + r) >> 1; Build(x * 2, l, Mid), Build(x * 2 + 1, Mid + 1 ,r); Sum[x] = Sum[x * 2] + Sum[x * 2 + 1];}void Preparation() { int top = 1; D[1] = 1; while (top) { int u = D[top]; if (!Flag[u]) { Flag[u] = 1, L[u] = R[u] = ++ cnt; Ord[cnt] = u; for (int p = Last[u]; p; p = Next[p]) { int v = Go[p]; if (L[v]) continue; D[++ top] = v, Pre[v] = u, Deep[v] = Deep[u] + 1; Fa[v][0] = u; } } else { for (int p = Last[u]; p; p = Next[p]) if (L[Go[p]] > L[u]) R[u] = max(R[u], R[Go[p]]); top --; } } for (int j = 1; j < 20; j ++) for (int i = 1; i <= N; i ++) Fa[i][j] = Fa[Fa[i][j - 1]][j - 1]; Build(1, 1, N);}void MakeRoot(int u) { Access(u), Splay(u); Rev[u] ^= 1, Root = u;}int main() { scanf("%d%d", &N, &Q); for (int i = 1; i < N; i ++) { int u, v; Read(u), Read(v); Link(u, v), Link(v, u); } Preparation(); Root = 1; for (int i = 1; i <= Q; i ++) { int u, Ord; Read(Ord), Read(u); if (Ord == 3) printf("%.8f\n", Query(u)); if (Ord == 1) Access(u); if (Ord == 2) MakeRoot(u); }}
- JZOJ4753【GDOI2017模拟9.4】种树 LCT维护子树信息+换根时维护Dfs序(CC MONOPLOY加强版)
- LCT维护子树信息(子树信息LCT) LCT维护边权(边权LCT) 知识点讲解
- bzoj4530 [Bjoi2014]大融合 (LCT维护子树信息)
- 【BJOI2014】大融合 LCT维护子树信息
- [BZOJ4530]-大融合-LCT维护子树信息
- [BZOJ3510][启发式合并][LCT维护子树信息]首都
- [BZOJ4530][Bjoi2014][LCT维护子树信息]大融合
- BZOJ 4530 [Bjoi2014]大融合 LCT维护子树信息
- BZOJ 3779 重组病毒 LCT维护子树信息
- bzoj 4530: [Bjoi2014]大融合 lct维护子树信息
- bzoj3510首都 LCT维护子树信息+启发式合并
- [BZOJ]4530 [BJOI2014] 大融合 LCT维护子树信息
- BZOJ4530 BJOI 2014 大融合 LCT维护子树信息
- BZOJ 4530: [Bjoi2014]大融合 lct维护子树信息
- BZOJ 3510: 首都 LCT维护子树信息 启发式合并
- JZOJ 3766【BJOI2014】大融合(lct维护子树大小)
- bzoj4530 [Bjoi2014]大融合(LCT维护子树大小)
- BZOJ 3779 重组病毒 LCT+线段树维护DFS序
- Glide深入浅出(二)——源码解析
- xcode打包不生成ipa文件而生成文件夹 及 app文件转成ipa
- 鸡仔单片机成长记----------------浅谈51堆栈操作
- HttpURLConnection连接服务器失败解决办法
- pull解析
- JZOJ4753【GDOI2017模拟9.4】种树 LCT维护子树信息+换根时维护Dfs序(CC MONOPLOY加强版)
- 【快速排序】QuickSort
- javascript面向对象-继承
- iOS开发中的对象系统基础
- dpdk多进程示例解读(examples/multi_process/simple_mp)
- Deep Residual Network学习(二)
- 移植u-boot学习笔记6-----修改代码支持nor flash
- 递归——单词全排列
- SSM框架—详细整合教程(Spring+SpringMVC+MyBatis)