【BZOJ 1036】[ZJOI2008]树的统计Count

1036: [ZJOI2008]树的统计Count

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 9697  Solved: 3931
[Submit][Status][Discuss]

Description

一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. 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


ANALISIS
裸树剖。注意负数就行了。
#include <cstdio>
#include <cstring>
#include <algorithm>
 
using namespace std;
 
const int MAXN = 30005;
int n;
 
struct Edge
{
    int from, to, next;
     
    Edge() {
    }
     
    Edge(int u, int v) : from(u), to(v) {
    }
     
}edges[MAXN << 1];
 
int first[MAXN], tots;
int fa[MAXN], top[MAXN], num[MAXN], dep[MAXN], bw[MAXN], sons[MAXN], cnt;
int maxv[MAXN << 2], sumv[MAXN << 2], _max, _sum;
 
void addedge(int u, int v)
{
    edges[tots] = Edge(u, v);
    edges[tots].next = first[u];
    first[u] = tots++;
}
 
void dfs1(int x, int d)
{
    dep[x] = d;
    int maxson = 0;
    sons[x] = 1;
    for (int i = first[x]; i != -1; i = edges[i].next)
    if (dep[edges[i].to] == 0)
    {
        dfs1(edges[i].to, d + 1);
        sons[x] += sons[edges[i].to];
        fa[edges[i].to] = x;
        if (sons[edges[i].to] > maxson)
        {
            maxson = sons[edges[i].to];
            bw[x] = i;
        }
    }
}
 
void dfs2(int x, int t)
{
    if (num[x]) return;
    num[x] = ++cnt;
    top[x] = t;
    if (bw[x] != -1) dfs2(edges[bw[x]].to, t);
    for (int i = first[x]; i != -1; i = edges[i].next)
        dfs2(edges[i].to, edges[i].to);
}
 
void update(int o, int L, int R, int v, int delx)
{
    if (L == R)
    {
        maxv[o] = sumv[o] = delx;
        return; 
    }
    int mid = (L + R) >> 1;
    int lc = o << 1, rc = lc + 1;
    if (mid >= v) update(lc, L, mid, v, delx);
    if (mid + 1 <= v) update(rc, mid + 1, R, v, delx);
    maxv[o] = max(maxv[lc], maxv[rc]);
    sumv[o] = sumv[lc] + sumv[rc];
}
 
void query(int o, int L, int R, int y1, int y2)
{
    if (y1 <= L && R <= y2)
    {
        _max = max(_max, maxv[o]);
        _sum += sumv[o];
        return;
    }
    int mid = (L + R) >> 1;
    int lc = o << 1, rc = lc + 1;
    if (mid >= y1) query(lc, L, mid, y1, y2);
    if (mid + 1 <= y2) query(rc, mid + 1, R, y1, y2);
}
 
int main()
{
    scanf("%d", &n);
    tots = 0;
    memset(first, -1, sizeof(first));
    for (int i = 1; i < n; ++i)
    {
        int a, b;
        scanf("%d%d", &a, &b);
        addedge(a, b);
        addedge(b, a);
    }
    memset(dep, 0, sizeof(dep));
    memset(sons, 0, sizeof(sons));
    memset(bw, -1, sizeof(bw));
    dfs1(1, 1);
    cnt = 0;
    memset(num, 0, sizeof(num));
    dfs2(1, 1);
    memset(sumv, 0, sizeof(sumv));
    for (int i = 1; i <= n; ++i)
    {
        int t;
        scanf("%d", &t);
        update(1, 1, n, num[i], t);
    }
    int q;
    scanf("%d", &q);
    while (q--)
    {
        char cmd[10];
        int a, b;
        scanf("%s %d%d", cmd, &a, &b);
        if (cmd[0] == 'C') update(1, 1, n, num[a], b);
        else
        {
            _max = -60001;
            _sum = 0;
            for (;;)
            {
                int f1 = top[a], f2 = top[b];
                if (f1 == f2) break;
                if (dep[f1] > dep[f2]) query(1, 1, n, num[f1], num[a]), a = fa[f1];
                else query(1, 1, n, num[f2], num[b]), b = fa[f2];
            }
            if (num[b] < num[a]) swap(a, b);
            query(1, 1, n, num[a], num[b]);
            if (cmd[1] == 'M') printf("%d\n", _max);
            else printf("%d\n", _sum);
        }
    }
    return 0;
}

 

posted @ 2015-12-11 20:16  albertxwz  阅读(178)  评论(0编辑  收藏  举报