[BZOJ3786]星系探索
[BZOJ3786]星系探索
试题描述
物理学家小C的研究正遇到某个瓶颈。
他正在研究的是一个星系,这个星系中有n个星球,其中有一个主星球(方便起见我们默认其为1号星球),其余的所有星球均有且仅有一个依赖星球。主星球没有依赖星球。
我们定义依赖关系如下:若星球a的依赖星球是b,则有星球a依赖星球b.此外,依赖关系具有传递性,即若星球a依赖星球b,星球b依赖星球c,则有星球a依赖星球c.
对于这个神秘的星系中,小C初步探究了它的性质,发现星球之间的依赖关系是无环的。并且从星球a出发只能直接到达它的依赖星球b.
每个星球i都有一个能量系数wi.小C想进行若干次实验,第i次实验,他将从飞船上向星球di发射一个初始能量为0的能量收集器,能量收集器会从星球di开始前往主星球,并收集沿途每个星球的部分能量,收集能量的多少等于这个星球的能量系数。
但是星系的构成并不是一成不变的,某些时刻,星系可能由于某些复杂的原因发生变化。
有些时刻,某个星球能量激发,将使得所有依赖于它的星球以及他自己的能量系数均增加一个定值。还有可能在某些时刻,某个星球的依赖星球会发生变化,但变化后依然满足依赖关系是无环的。
现在小C已经测定了时刻0时每个星球的能量系数,以及每个星球(除了主星球之外)的依赖星球。接下来的m个时刻,每个时刻都会发生一些事件。其中小C可能会进行若干次实验,对于他的每一次实验,请你告诉他这一次实验能量收集器的最终能量是多少。
输入
第一行一个整数n,表示星系的星球数。
接下来n-1行每行一个整数,分别表示星球2-n的依赖星球编号。
接下来一行n个整数,表示每个星球在时刻0时的初始能量系数wi.
接下来一行一个整数m,表示事件的总数。
事件分为以下三种类型。
(1)"Q di"表示小C要开始一次实验,收集器的初始位置在星球di.
(2)"C xi yi"表示星球xi的依赖星球变为了星球yi.
(3)"F pi qi"表示星球pi能量激发,常数为qi.
输出
输入示例
3 1 1 4 5 7 5 Q 2 F 1 3 Q 2 C 2 3 Q 2
输出示例
9 15 25
数据规模及约定
n<=100000,m<=300000,1<di,xi<=n,wi,qi<=100000.保证操作合法。
题解
这题的妙点在于 dfs 序的优美,注意这题要的是把每个点拆成入栈时刻和出栈时刻两个点,设节点 i 的入栈时刻为 dli,出栈时刻为 dri,点权为 val[i],那么设 v[dli] = val[i],v[dri] = -val[i],同时记一个标记 s,s[dli] = 1, s[dri] = -1。现在考虑不带换父亲操作,点 i 到根节点的距离等于 Σv[j] (1 ≤ j ≤ dli);修改某子树权值可以视为序列上的区间修改,假设要修改子树 i,则将区间 [dli, dri] 打上懒标记 addv,下传标记的时候该区间维护的权值和加上 Σs[j] (dli ≤ j ≤ dri) * addv 即可,正确性留给读者证(y)明(y)。
上面的东西可以用线段树维护。至于加上了换父亲(C)操作,就可以用 splay 来搞,C操作显然是将一段区间移位,那么可以通过一系列伸展树的分裂、合并操作完成(详细地说就是将指定区间分离出来,再插入到目标位置里,再详细一点请参见代码)。F操作可以将指定区间分离出来,打一个懒标记,再合并成原序列。splay 的标记下传规则跟线段树的一样。
能写出代码,这题就能 AC 了= =。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | #include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <stack> #include <vector> #include <queue> #include <cstring> #include <string> #include <map> #include <set> using namespace std; const int BufferSize = 1 << 16; char buffer[BufferSize], *Head, *Tail; inline char Getchar() { if (Head == Tail) { int l = fread(buffer, 1, BufferSize, stdin); Tail = (Head = buffer) + l; } return *Head++; } int read() { int x = 0, f = 1; char c = Getchar(); while (!isdigit(c)){ if (c == '-' ) f = -1; c = Getchar(); } while (isdigit(c)){ x = x * 10 + c - '0' ; c = Getchar(); } return x * f; } #define maxn 100010 #define maxm 200010 #define LL long long int n; int m, head[maxn], next[maxm], to[maxm]; int clo, val[maxn], dl[maxn], dr[maxn], ids[maxn<<1], dv[maxn<<1], ds[maxn<<1]; void AddEdge( int a, int b) { to[++m] = b; next[m] = head[a]; head[a] = m; swap(a, b); to[++m] = b; next[m] = head[a]; head[a] = m; return ; } void build( int u, int fa) { dl[u] = ++clo; dv[clo] = val[u]; ds[clo] = 1; for ( int e = head[u]; e; e = next[e]) if (to[e] != fa) build(to[e], u); dr[u] = ++clo; dv[clo] = -val[u]; ds[clo] = -1; return ; } struct Node { int sym, sums; LL val, sumv, addv; Node() { val = sumv = addv = sym = sums = 0; } void clear() { val = sumv = addv = sym = sums = 0; return ; } } nodes[maxn<<1]; int ToT, root, ch[maxn<<1][2], fa[maxn<<1]; void maintain( int u) { nodes[0].clear(); Node &o = nodes[u], &l = nodes[ch[u][0]], &r = nodes[ch[u][1]]; o.sums = l.sums + o.sym + r.sums; o.sumv = l.addv * l.sums + l.sumv + o.val + r.addv * r.sums + r.sumv; return ; } void builds( int & u, int pa, int L, int R) { if (L > R){ u = 0; return ; } int M = L + R >> 1; Node& o = nodes[u = ++ToT]; o.sym = o.sums = ds[M]; o.val = o.sumv = dv[M]; o.addv = 0; ids[M] = u; fa[u] = pa; builds(ch[u][0], u, L, M - 1); builds(ch[u][1], u, M + 1, R); maintain(u); return ; } void pushdown( int u) { Node &o = nodes[u], &l = nodes[ch[u][0]], &r = nodes[ch[u][1]]; if (o.addv) { // printf("%lld ", o.sumv); o.sumv += o.addv * o.sums; o.val += o.addv * o.sym; l.addv += o.addv; r.addv += o.addv; // printf("pushdown: (u)%d (o.addv)%lld (o.sumv)%lld\n", u, o.addv, o.sumv); o.addv = 0; } nodes[0].clear(); return ; } void rotate( int u) { int y = fa[u], z = fa[y], l = 0, r = 1; if (ch[y][1] == u) swap(l, r); if (z) ch[z][ch[z][1]==y] = u; fa[u] = z; fa[y] = u; fa[ch[u][r]] = y; ch[y][l] = ch[u][r]; ch[u][r] = y; maintain(y); maintain(u); return ; } int St[maxn], top; void splay( int u) { int t = u; while (fa[t]) St[++top] = t, t = fa[t]; St[++top] = t; while (top) pushdown(St[top--]); while (fa[u]) { int y = fa[u], z = fa[y]; if (!z) rotate(u); else { if ((ch[z][0] == y) ^ (ch[y][0] == u)) rotate(u); else rotate(y); rotate(u); } } return ; } int splitl( int u) { splay(u); int ret = ch[u][0]; Node &o = nodes[u], &l = nodes[ch[u][0]]; nodes[0].clear(); o.sumv -= (l.sumv + l.addv * l.sums); fa[ret] = 0; ch[u][0] = 0; return ret; } int splitr( int u) { splay(u); int ret = ch[u][1]; Node &o = nodes[u], &r = nodes[ch[u][1]]; nodes[0].clear(); o.sumv -= (r.sumv + r.addv * r.sums); fa[ret] = 0; ch[u][1] = 0; return ret; } void update( int u, int v) { splay(u); nodes[u].addv += v; return ; } void merge( int a, int b) { if (!a || !b) return ; while (ch[a][1]) a = ch[a][1]; while (ch[b][0]) b = ch[b][0]; splay(a); splay(b); Node &o = nodes[b], &l = nodes[a]; o.sumv += (l.sumv + l.addv * l.sums); fa[a] = b; ch[b][0] = a; return ; } int main() { n = read(); for ( int i = 2; i <= n; i++) AddEdge(i, read()); for ( int i = 1; i <= n; i++) val[i] = read(); build(1, 0); builds(root, 0, 1, n << 1); int q = read(); while (q--) { char tp = Getchar(); while (!isalpha(tp)) tp = Getchar(); if (tp == 'Q' ) { int x = dl[read()]; splay(ids[x]); Node& o = nodes[ids[x]], &r = nodes[ch[ids[x]][1]]; LL ans = o.sumv + o.addv * o.sums - r.sumv - r.addv * r.sums; printf( "%lld\n" , ans); } if (tp == 'F' ) { int x = read(), v = read(), xl = dl[x], xr = dr[x], lt = 0, rt = 0; lt = splitl(ids[xl]); rt = splitr(ids[xr]); update(ids[xl], v); merge(lt, ids[xl]); merge(ids[xr], rt); } if (tp == 'C' ) { int x = read(), fax = read(), xl = dl[x], xr = dr[x], lt, rt; lt = splitl(ids[xl]); rt = splitr(ids[xr]); merge(lt, rt); rt = splitr(ids[dl[fax]]); lt = ids[dl[fax]]; merge(lt, ids[xl]); merge(ids[xr], rt); } } return 0; } |
不知为何慢的飞起,会不会是因为我用的数组版 splay?求帮忙优化orz。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步