CSU-2132 美食群岛(树套树+树剖+hash)

Description
Wells来到了一个充满美食的群岛!

这个世界是由N个岛屿构成,由N-1座桥将这N个岛屿连接起来,每个岛屿上只生产一种美食,每个岛屿上美食都是不同的,第i种美食会给Wells带来一个幸福度 wi ,当然不同的美食给Wells带来的幸福度可能是相同的。

作为一个曾经的吃货,对于美食还是非常挑剔的,Wells秉持中庸之道,只会吃带来幸福度在[a,b]中的美食而且每种只会吃一次(毕竟最近Wells的压力真的非常大,吃不下太多……),当然不同时候Wells所认定的a,b是不同的。

现在Wells需要游历美食群岛,Wells想知道如果这时候从u出发到达v,在当时给定的[a,b]下,他最多可以获得多少幸福度。

当然,美食群岛也是一个动态的变动系统,也会在某个时刻更改生产美食的种类,更新幸福度。

那么问题来了,Wells很懒,需要聪明的你回答他的每次询问。

Input
多组数据,对于每组数据:

第一行给定两个整数 n,m(1≤n,m≤10^5), 表示岛屿个数和Wells的询问个数.

第二行 c1,c2,…,cn(1≤ci≤10^7),表示第i个岛屿的美食带给Wells的幸福度

接下来n-1行,每行两个整数x,y(1≤x,y≤n),表明第x个岛屿与第y个岛屿之间有一座桥相连。

接下来m行,每行开始有一个字符表明询问或者修改信息

若以Q开头,代表是询问信息,Q后将紧跟4个数字 s,t,a,b(1≤s,t≤n;1≤a≤b≤10^7)表明出发城市,目标城市,Wells选定的幸福度的区间。

若以C开头,代表修改操作,C后紧跟两个数字 x,y(x≤n,;1≤y≤10^7),表示将第x个岛屿的美食幸福度改为y。

Output
对于每个Q询问,输出一行,表示从s->t路径上满足[a,b]限制情况下Wells最大能获得的幸福度。

Sample Input
5 3
1 2 1 3 2
1 2
2 4
3 1
2 5
Q 4 5 1 3
Q 1 1 1 1
Q 3 5 2 3
Sample Output
7
1
4
传送门:戳这里
题解:树上链的问题,首先想到用树剖,但这道题要求求出链上所有权值在[a,b]之间的权值和,因此需要用树套树,再加上权值的范围是1e7,因此还需要把权值离散一下
此题还可以用CDQ分治求解,解题报告:戳这里

#include<cstdio>
#include<string.h>
#include<iostream>
#include<assert.h>
#include<stack>
#include<queue>
#include<algorithm>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long LL;

const int MX = 1e5 + 5;
const int inf = 0x3f3f3f3f;


struct Edge {
    int v, nxt;
} E[MX * 2];
int head[MX], tot;
int top[MX], f[MX], dep[MX], sz[MX], son[MX], p[MX], fp[MX], totp;

void init() {
    memset (head, -1, sizeof (head) );
    tot = 0;
}
void add_edge (int u, int v) {
    E[tot].v = v;
    E[tot].nxt = head[u];
    head[u] = tot++;
}
void dfs (int u, int fa, int deep) {
    f[u] = fa; dep[u] = deep;
    sz[u] = 1; son[u] = 0;
    for (int i = head[u]; ~i; i = E[i].nxt) {
        int v = E[i].v;
        if (v == fa) continue;
        dfs (v, u, deep + 1);
        sz[u] += sz[v];
        if (sz[v] > sz[son[u]]) son[u] = v;
    }
}
void rebuild (int u, int t) {
    top[u] = t;
    fp[totp] = u; p[u] = totp++;
    if (son[u]) rebuild (son[u], t);
    else return;
    for (int i = head[u]; ~i; i = E[i].nxt) {
        int v = E[i].v;
        if (v == f[u] || v == son[u]) continue;
        rebuild (v, v);
    }
}
void pre_solve (int n) {
    totp = 1;
    dfs (1, 0, 1);
    rebuild (1, 1);
}

const int MXM = 2e7 + 5;
struct Tree {
    int n, m;
    vector <int> root;
    int cnt;
    LL sum[MXM];
    int ls[MXM], rs[MXM];
    void init (int _n, int _m) {
        n = _n, m = _m;
        cnt = 0;
        root.clear();
        root.resize (n + 1);
    }

    void update (int p, int v, int l, int r, int prt, int &rt) {
        rt = ++cnt;
        ls[rt] = ls[prt]; rs[rt] = rs[prt];
        sum[rt] = sum[prt] + v;
        if (l == r) return;
        int m = (l + r) >> 1;
        if (p <= m) update (p, v, l, m, ls[prt], ls[rt]);
        else update (p, v, m + 1, r, rs[prt], rs[rt]);
    }
    LL query (int L, int R, int l, int r, int rt) {
        if (L <= l && R >= r) return sum[rt];
        int m = (l + r) >> 1; LL ret = 0;
        if (L <= m) ret += query (L, R, l, m, ls[rt]);
        if (R > m) ret += query (L, R, m + 1, r, rs[rt]);
        return ret;
    }
    void Update (int x, int y, int v) {
        for (int i = x; i <= n; i += i & -i) update (y, v, 1, m, root[i], root[i]);
    }
    LL pre_sum (int x, int l, int r) {
        if (x > n) x = n;
        LL ret = 0;
        for (int i = x; i > 0; i -= i & -i)
            ret += query (l, r, 1, m, root[i]);
        return ret;
    }
    LL Query (int L, int R, int l, int r) {
        return pre_sum (R, l, r) - pre_sum (L - 1, l, r);
    }
} T;


struct Que {
    int op, u, v, a, b, x, y;
} q[MX];
int h[MX * 4], rear;
int val[MX];

int main() {
    int n, m;
    char op[2]; int u, v, a, b, x, y;
    //freopen ("in.txt", "r", stdin);
    while (~scanf ("%d%d", &n, &m) ) {
        rear = 0;
        init();
        for (int i = 1; i <= n; i++) scanf ("%d", &val[i]), h[++rear] = val[i];
        for (int i = 1; i < n; i++) {
            scanf ("%d%d", &u, &v);
            add_edge (u, v);
            add_edge (v, u);
        }
        pre_solve (n);

        for (int i = 1; i <= m; i++) {
            scanf ("%s", op);
            if (op[0] == 'Q') {
                scanf ("%d%d%d%d", &u, &v, &a, &b);
                q[i] = (Que) {1, u, v, a, b, 0, 0};
                h[++rear] = a;
                h[++rear] = b;
            } else {
                scanf ("%d%d", &x, &y);
                q[i] = (Que) {2, 0, 0, 0, 0, x, y};
                h[++rear] = y;
            }
        }
        sort (h + 1, h + rear + 1);
        rear = unique (h + 1, h + rear + 1) - h - 1;
        T.init (n, rear);
        for (int i = 1; i <= n; i++) {
            int pos = lower_bound (h + 1, h + rear + 1, val[fp[i]]) - h;
            T.Update (i, pos, val[fp[i]]);
        }
        for (int i = 1; i <= m; i++) {
            if (q[i].op == 1) {
                u = q[i].u, v = q[i].v, a = q[i].a, b = q[i].b;
                a = lower_bound (h + 1, h + rear + 1, a) - h;
                b = lower_bound (h + 1, h + rear + 1, b) - h;
                int f1 = top[u], f2 = top[v];
                LL ans = 0;
                while (f1 != f2) {
                    if (dep[f1] < dep[f2]) {
                        swap (u, v);
                        swap (f1, f2);
                    }
                    ans += T.Query (p[f1], p[u], a, b);
                    u = f[f1], f1 = top[u];
                }
                if (dep[u] > dep[v]) swap (u, v);
                ans += T.Query (p[u], p[v], a, b);
                printf ("%lld\n", ans);
            } else {
                x = q[i].x, y = q[i].y;
                int p1 = lower_bound (h + 1, h + rear + 1, val[x]) - h;
                int p2 = lower_bound (h + 1, h + rear + 1, y) - h;
                T.Update (p[x], p1, -val[x]);
                T.Update (p[x], p2, y);
                val[x] = y;
            }
        }
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_31759205/article/details/80562041