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;
}

 

posted @ 2019-07-21 10:06  红色OI再临  阅读(139)  评论(0编辑  收藏  举报