• 【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
    ", _max);
                else printf("%d
    ", _sum);
            }
        }
        return 0;
    }
  • 相关阅读:
    20161101学习笔记
    20161031学习笔记
    20161028学习笔记
    20161027学习笔记
    ReentrantLock Condition
    ReentrantLock 重入锁
    CountDownLatch用法与原理
    场景化解释 AQS原理
    Atomic
    多线程工具类
  • 原文地址:https://www.cnblogs.com/albert7xie/p/5040131.html
Copyright © 2020-2023  润新知