1036: [ZJOI2008]树的统计Count

1036: [ZJOI2008]树的统计Count
Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 21046 Solved: 8535
[Submit][Status][Discuss]
Description
  一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成
一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I
II. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身

Input
  输入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有
一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数q,表示操作
的总数。接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。
对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。

Output
  对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。

Sample Input
4

1 2

2 3

4 1

4 2 1 3

12

QMAX 3 4

QMAX 3 3

QMAX 3 2

QMAX 2 3

QSUM 3 4

QSUM 2 1

CHANGE 1 5

QMAX 3 4

CHANGE 3 6

QMAX 3 4

QMAX 2 4

QSUM 3 4
Sample Output
4

1

2

2

10

6

5

6

5

16
HINT
Source

树链剖分基础题啊,对于一颗树的一对节点的路径的查询与修改,首先想到线段树是操作区间的,那么问题可以转换为把树剖分为一条很长的链当作区间,而这条长链又由重链和轻链构成,暂且不管这个重链轻链是啥,首先你得想到,这个链由树上的节点构成,而他们的顺序是怎么样的呢,这时候就是要搞定他们之间的顺序了,于是便有了大佬们的重链与轻链之说,重链由这样一些结点构成,即以它为根的子树中结点数目是它父节点中以其他子节点为根的子树中结点数目最多的那个结点,把它称作重结点,而根据我的理解,只有叶节点是轻结点,且重链就是由这些重结点由重边连接而成的,重边就是说,由父节点向重结点的边,轻链就是由轻边构成的,如果把一棵树分成这样一些重链与轻链的话,便也可以通过重链与轻链来标号,重链中的优先标号,这就使得在同一条链上的在线段树中建立的区间中是连续的,具体要怎么查询的操作,这里就不写了,建议先去看看LCA,最近公共祖先。

#include<iostream>
#include<cstdio>
#include<string>
#include <cstring>
#include <stack>
#include <algorithm>
#include <map>
#include <queue>
using namespace std;
#define INF 0x3f3f3f3f
int n, cnt, ra[30005];
vector<int> G[30005];
struct node {
    int siz, sta, depth, father, son, tid, val;
}a[30005];
struct tree {
    int l, r;
    int sum, Max;
}b[120005];
void addedge(int x,int y) {
    G[x].push_back(y);
    G[y].push_back(x);
}
void dfs1(int u,int f,int depth) {
    a[u].siz = 1;
    a[u].father = f;
    a[u].depth = depth;
    int si = G[u].size();
    for (int i = 0; i < si; ++i) {
        int t = G[u][i];
        if (t != f) {
            dfs1(t, u, depth + 1);
            a[u].siz += a[t].siz;
            if (a[u].son == -1 || a[t].siz > a[a[u].son].siz) {
                a[u].son = t;
            }
        }
    }
}
void dfs2(int u,int t) {
    a[u].tid = cnt;
    a[u].sta = t;
    ra[cnt] = u;
    cnt++;
    if (a[u].son == -1) {//到达叶节点
        return;
    }
    dfs2(a[u].son,t);
    int si = G[u].size();
    for (int i = 0; i < si; ++i) {
        int t = G[u][i];
        if (t != a[u].father && t != a[u].son) {
            dfs2(t, t);
        }
    }
}
void buildTree(int l,int r,int o) {
    b[o].l  = l;
    b[o].r = r;
    if (l == r) {
        b[o].Max = b[o].sum = a[ra[l]].val;
        return;
    }
    int lo = o << 1, ro = (o << 1) | 1, mid = (l + r) >> 1;
    buildTree(l, mid,lo);
    buildTree(mid + 1, r, ro);
    b[o].sum = b[lo].sum + b[ro].sum;
    b[o].Max = max(b[lo].Max, b[ro].Max);
}
int queryTree(int l,int r,int o,int op) {
    if (op == 0) {
        if (b[o].r < l || b[o].l > r) {
            return 0;
        }
        if (b[o].r <= r && b[o].l >= l) {
            return b[o].sum;
        }
        return queryTree(l, r, o << 1,op) + queryTree(l, r, (o << 1) | 1,op);
    }
    else {
        if (b[o].r < l || b[o].l > r) {
            return -INF;
        }
        if (b[o].r <= r && b[o].l >= l) {
            return b[o].Max;
        }
        return max(queryTree(l, r, o << 1, op),queryTree(l, r, (o << 1) | 1, op));
    }
}
void updateTree(int l, int o,int value) {
    if (b[o].l == l && b[o].r == l) {
        b[o].sum = value;
        b[o].Max = b[o].sum;
        return;
    }
    int mid = (b[o].l + b[o].r) >> 1, lo = o << 1, ro = (o << 1) | 1;
    if (l <= mid) {
        updateTree(l, lo, value);
    }
    else {
        updateTree(l, ro, value);
    }
    b[o].sum = b[lo].sum + b[ro].sum;
    b[o].Max = max(b[lo].Max, b[ro].Max);
}
int query(int u,int v,int op) {
    int fu = a[u].sta;
    int fv = a[v].sta;
    int sum = 0;
    if (op == 1) {
        sum = -INF;
    }
    while (fu != fv) {
        if (a[fu].depth >= a[fv].depth) {
            if (op == 0)
                sum += queryTree(a[fu].tid, a[u].tid, 1, op);
            else
                sum = max(sum, queryTree(a[fu].tid, a[u].tid, 1, op));
            u = a[fu].father;
        }
        else {
            if (op == 0)
                sum += queryTree(a[fv].tid, a[v].tid, 1, op);
            else
                sum = max(sum, queryTree(a[fv].tid, a[v].tid, 1, op));
            v = a[fv].father;
        }
        fu = a[u].sta;
        fv = a[v].sta;
    }
    if (u != v) {
        if (a[u].depth >= a[v].depth) {
            if (op == 0)
                sum += queryTree(a[v].tid, a[u].tid, 1, op);
            else
                sum = max(sum, queryTree(a[v].tid, a[u].tid, 1, op));
        }
        else {
            if (op == 0)
                sum += queryTree(a[u].tid, a[v].tid, 1, op);
            else
                sum = max(sum, queryTree(a[u].tid, a[v].tid, 1, op));
        }
    }
    else {
        if (op == 0)
            sum += queryTree(a[u].tid, a[v].tid, 1, op);
        else
            sum = max(sum, queryTree(a[u].tid, a[v].tid, 1, op));
    }
    return sum;
}
int main() {
    char op[15];
    while (~scanf("%d",&n)) {
        int x, y;
        for (int i = 0; i < n - 1; ++i) {
            scanf("%d%d", &x, &y);
            addedge(x, y);
        }
        for (int i = 1; i <= n; ++i) {
            a[i].son = -1;
        }
        cnt = 1;
        dfs1(1, -1, 1);
        dfs2(1, 1);
        for (int i = 1; i <= n; ++i) {
            scanf("%d", &a[i].val);
        }
        buildTree(1,n,1);
        int q;
        scanf("%d", &q);
        while (q--) {
            scanf("%s%d%d", op, &x, &y);
            if (op[0] == 'Q') {
                if (op[1] == 'S') {
                    printf("%d\n", query(x,y,0));
                }
                else {
                    printf("%d\n", query(x, y, 1));
                }
            }
            else {
                updateTree(a[x].tid, 1, y);
            }
        }
        for (int i = 1; i <= n; ++i) {
            G[i].clear();
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/jack_zhuiyi/article/details/79811049