codeforces 916 E. Jamie and Tree
可以这很省选模拟题
首先可以想到一个神奇的做法
对于换根和子树操作,可以用ETT维护dfs序实现
对于查询lca,可以用LCT维护动态树实现
当然这不太可写,不妨优化一下
查询lca可以看成是求出lca(root,u),lca(root,v),设它们为lca1, lca2
如果lca1 == lca2,则lca为lca(u,v)
否则lca为lca1和lca2中深度最大的那个
画个图可以明显直观的得到如上结论
发现树的形态没有改变,只是换根,那么可以讨论一下root和p的关系实现子树操作
如果p是root,那么就是1~n
如果p在root内或者不与root相交,那么就是dfs序上dfn[p]~dfn[p]+sz[p]-1
如果p在root外,要计算一下root到p的路径上p的儿子x,那么就是dfs序上1~n减去dfn[x]~dfn[x]+sz[x]-1
树状数组维护区间加、区间求和
1 %:pragma GCC optimize(2) 2 %:pragma GCC optimize(3) 3 %:pragma GCC optimize("Ofast") 4 %:pragma GCC optimize("inline") 5 %:pragma GCC optimize("-fgcse") 6 %:pragma GCC optimize("-fgcse-lm") 7 %:pragma GCC optimize("-fipa-sra") 8 %:pragma GCC optimize("-ftree-pre") 9 %:pragma GCC optimize("-ftree-vrp") 10 %:pragma GCC optimize("-fpeephole2") 11 %:pragma GCC optimize("-ffast-math") 12 %:pragma GCC optimize("-fsched-spec") 13 %:pragma GCC optimize("unroll-loops") 14 %:pragma GCC optimize("-falign-jumps") 15 %:pragma GCC optimize("-falign-loops") 16 %:pragma GCC optimize("-falign-labels") 17 %:pragma GCC optimize("-fdevirtualize") 18 %:pragma GCC optimize("-fcaller-saves") 19 %:pragma GCC optimize("-fcrossjumping") 20 %:pragma GCC optimize("-fthread-jumps") 21 %:pragma GCC optimize("-funroll-loops") 22 %:pragma GCC optimize("-fwhole-program") 23 %:pragma GCC optimize("-freorder-blocks") 24 %:pragma GCC optimize("-fschedule-insns") 25 %:pragma GCC optimize("inline-functions") 26 %:pragma GCC optimize("-ftree-tail-merge") 27 %:pragma GCC optimize("-fschedule-insns2") 28 %:pragma GCC optimize("-fstrict-aliasing") 29 %:pragma GCC optimize("-fstrict-overflow") 30 %:pragma GCC optimize("-falign-functions") 31 %:pragma GCC optimize("-fcse-skip-blocks") 32 %:pragma GCC optimize("-fcse-follow-jumps") 33 %:pragma GCC optimize("-fsched-interblock") 34 %:pragma GCC optimize("-fpartial-inlining") 35 %:pragma GCC optimize("no-stack-protector") 36 %:pragma GCC optimize("-freorder-functions") 37 %:pragma GCC optimize("-findirect-inlining") 38 %:pragma GCC optimize("-fhoist-adjacent-loads") 39 %:pragma GCC optimize("-frerun-cse-after-loop") 40 %:pragma GCC optimize("inline-small-functions") 41 %:pragma GCC optimize("-finline-small-functions") 42 %:pragma GCC optimize("-ftree-switch-conversion") 43 %:pragma GCC optimize("-foptimize-sibling-calls") 44 %:pragma GCC optimize("-fexpensive-optimizations") 45 %:pragma GCC optimize("-funsafe-loop-optimizations") 46 %:pragma GCC optimize("inline-functions-called-once") 47 %:pragma GCC optimize("-fdelete-null-pointer-checks") 48 49 #include <bits/stdc++.h> 50 using namespace std; 51 const int N = 3e5 + 10; 52 typedef long long ll; 53 54 int n, q, w[N]; 55 56 int head[N], rest[N * 2], to[N * 2], tot; 57 58 int pos[N], l[N], r[N]; ll val[N]; 59 60 void add(int u, int v) { 61 to[++ tot] = v, rest[tot] = head[u], head[u] = tot; 62 } 63 64 int root; 65 66 ll c1[N], c2[N]; 67 68 void bt_add(int x, ll y) { 69 for(int i = x ; i <= n ; i += i & -i) c1[i] += y, c2[i] += x * y; 70 } 71 72 ll bt_query(int x) { 73 ll res = 0; 74 for(int i = x ; i ; i -= i & -i) res += (x + 1) * c1[i] - c2[i]; 75 return res; 76 } 77 78 inline void modify(int l, int r, ll x) { 79 bt_add(l, x), bt_add(r + 1, -x); 80 } 81 82 inline ll query(int l, int r) { 83 ll suml = val[l - 1] + bt_query(l - 1); 84 ll sumr = val[r] + bt_query(r); 85 return sumr - suml; 86 } 87 88 int fa[N][21], dep[N], clk; 89 90 inline int gettruelca(int u, int v) { 91 if(dep[u] < dep[v]) swap(u, v); 92 for(int i = 18 ; ~ i ; -- i) if(dep[fa[u][i]] >= dep[v]) u = fa[u][i]; 93 if(u == v) return u; 94 for(int i = 18 ; ~ i ; -- i) if(fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i]; 95 return fa[u][0]; 96 } 97 98 inline bool inroot(int u) { 99 return l[root] <= pos[u] && pos[u] <= r[root]; 100 } 101 102 int getlca(int u, int v) { 103 int lca1 = gettruelca(root, u); 104 int lca2 = gettruelca(root, v); 105 if(lca1 == lca2) return gettruelca(u, v); 106 else return dep[lca1] > dep[lca2] ? lca1 : lca2; 107 } 108 109 void dfs(int u) { 110 l[u] = pos[u] = ++ clk; 111 val[clk] = w[u]; 112 dep[u] = dep[fa[u][0]] + 1; 113 for(int i = head[u] ; i ; i = rest[i]) { 114 int v = to[i]; 115 if(v == fa[u][0]) continue; 116 fa[v][0] = u; 117 dfs(v); 118 } 119 r[u] = clk; 120 } 121 122 int getson(int gra) { 123 int u = root; 124 for(int i = 18 ; ~ i ; -- i) if(dep[fa[u][i]] > dep[gra]) u = fa[u][i]; 125 return u; 126 } 127 128 void modify(int u, int x) { 129 if(inroot(u)) { 130 if(u != root) modify(l[u], r[u], x); 131 else modify(1, n, x); 132 } else { 133 int p = getson(u); 134 if(fa[p][0] == u) { 135 modify(1, n, x), modify(l[p], r[p], -x); 136 } else { 137 modify(l[u], r[u], x); 138 } 139 } 140 } 141 142 ll query(int u) { 143 if(inroot(u)) { 144 if(u != root) return query(l[u], r[u]); 145 else return query(1, n); 146 } else { 147 int p = getson(u); 148 if(fa[p][0] == u) { 149 return query(1, n) - query(l[p], r[p]); 150 } else { 151 return query(l[u], r[u]); 152 } 153 } 154 } 155 156 int main() { 157 scanf("%d%d", &n, &q); 158 for(int i = 1 ; i <= n ; ++ i) scanf("%d", &w[i]); 159 for(int i = 1, u, v ; i < n ; ++ i) { 160 scanf("%d%d", &u, &v); 161 add(u, v), add(v, u); 162 } 163 164 root = 1; 165 dfs(1); 166 for(int j = 1 ; j <= 18 ; ++ j) 167 for(int i = 1 ; i <= n ; ++ i) 168 fa[i][j] = fa[fa[i][j - 1]][j - 1]; 169 for(int i = 1 ; i <= n ; ++ i) val[i] += val[i - 1]; 170 171 for(int i = 1, op, u, v, x ; i <= q ; ++ i) { 172 scanf("%d", &op); 173 if(op == 1) { 174 scanf("%d", &root); 175 } else if(op == 2) { 176 scanf("%d%d%d", &u, &v, &x); 177 modify(getlca(u, v), x); 178 } else if(op == 3) { 179 scanf("%d", &u); 180 printf("%lld\n", query(u)); 181 } 182 } 183 }