2590 树的统计
看到lct的题解比较少,所以我来贡献一篇
注意的地方and坑点
1. 只用把mmax [ 0 ](维护的最大值)初始化为极小值
2. sum [ i ] , mmax [ i ]在输入时就可赋值为val [ i ]
3. 要先储存下联通的点,在输入完val后再进行link操作
CHANGE操作
change ( x , v )表示把 val [ x ] 改成v
步骤:
1. 将x点splay到根
2. 更新 val [ x ] = v
3. 进行pushup(x)操作
QMAX and QSUM操作
输入x,y表示询问x,y路径上的最大权值或者路径和
步骤
1. 只需split ( x , y ),然后输出 mmax [ y ] 或者 sum [ y ] 即可
2. 此时 mmax [ y ] 或 sum [ y ] 表示的就是x到y这条链上的最大权值 或者 权值和了
#include <iostream> #include <cmath> #include <cstring> #include <cstdio> #include <algorithm> #define MN 4000001 #define re register int #define ll long long #define inf 0x7fffffff using namespace std; int f[MN], val[MN], sum[MN], r[MN], son[MN][2]; int mmax[MN], size[MN]; int fake1[MN], fake2[MN]; int zhan[MN]; int n, m, cnt; int get(int x) { ////判断节点是否为一个Splay的根(与普通Splay的区别1) return son[f[x]][0] == x || son[f[x]][1] == x; } ////如果连的是轻边,他的父亲的儿子里没有它 void pushup(int x) { sum[x] = sum[son[x][0]] + sum[son[x][1]] + val[x]; mmax[x] = max(max(mmax[son[x][0]], mmax[son[x][1]]), val[x]); } void filp(int x) { swap(son[x][0], son[x][1]); r[x] ^= 1; } void pushdown(int x) { if (!r[x]) return; r[x] = 0; if (son[x][0]) filp(son[x][0]); if (son[x][1]) filp(son[x][1]); } void rotate(int x) { int y = f[x], z = f[y], k = (son[y][1] == x), s = son[x][!k]; if (get(y)) son[z][son[z][1] == y] = x; son[x][!k] = y; son[y][k] = s; if (s) f[s] = y; f[y] = x; f[x] = z; pushup(y); // pushup(x); } void splay(int x) { int y = x, top = 0; zhan[++top] = y; while (get(y)) zhan[++top] = f[y], y = f[y]; while (top) pushdown(zhan[top--]); while (get(x)) { y = f[x], top = f[y]; if (get(y)) rotate((son[y][0] == x) ^ (son[top][0] == y) ? x : y); rotate(x); } pushup(x); return; } void access(int x) { for (re y = 0; x; y = x, x = f[x]) { splay(x); son[x][1] = y; pushup(x); } } void makeroot(int x) { access(x); splay(x); filp(x); } int findroot(int x) { access(x); splay(x); while (son[x][0]) pushdown(x), x = son[x][0]; splay(x); return x; } void split(int x, int y) { makeroot(x); access(y); splay(y); } void cut(int x, int y) { split(x, y); if (findroot(y) == x && f[y] == x && !son[y][0]) { f[y] = son[x][1] = 0; pushup(x); } return; } void link(int x, int y) { makeroot(x); if (findroot(y) != x) f[x] = y; } void change(int x, int v) { splay(x); val[x] = v; pushup(x); } int main() { mmax[0] = -inf; scanf("%d", &n); for (re i = 1; i <= n - 1; i++) { scanf("%d%d", &fake1[i], &fake2[i]); } //先储存下要link的点,等输入完val后再操作 //巨坑 for (re i = 1; i <= n; i++) { scanf("%d", &val[i]); sum[i] = mmax[i] = val[i]; } int t; for (re i = 1; i <= n - 1; i++) link(fake1[i], fake2[i]); scanf("%d", &t); for (re i = 1; i <= t; i++) { char s[7]; int a1, a2; scanf("%s", s); scanf("%d%d", &a1, &a2); if (s[0] == 'C') { change(a1, a2); } if (s[0] == 'Q' && s[1] == 'M') { split(a1, a2); printf("%d\n", mmax[a2]); } if (s[0] == 'Q' && s[1] == 'S') { split(a1, a2); printf("%d\n", sum[a2]); } } // for(re i=1;i<=n;i++) // printf("%d %d\n",mmax[i],sum[i]); return 0; }
缘分让我们相遇乱世以外,
命运却要我们危难中相爱。
也许未来遥远在光年之外,
我愿守候未知里为你等待。