2590 树的统计

Posted zw130-lzr-blogs

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;

 

以上是关于2590 树的统计的主要内容,如果未能解决你的问题,请参考以下文章

luoguP2590 [ZJOI2008]树的统计(树链剖分)

P2590 [ZJOI2008]树的统计(树链剖分)

P2590 [ZJOI2008]树的统计

P2590 [ZJOI2008]树的统计

luogu2590 [ZJOI2008]树的统计

2590 树的统计