CSU-2132 美食群岛(CDQ分治+树剖)

2132: 美食群岛
Time Limit: 5 Sec Memory Limit: 512 Mb Submitted: 30 Solved: 14
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行,每行开始有一个字符表明询问或者修改信息

扫描二维码关注公众号,回复: 1870719 查看本文章

若以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
传送门:戳这里
题解:树上链的问题首先想到用树剖,然后将两种操作用CDQ分治优化,下面讨论查询和修改两种操作:
①因为要求链上权值在[a,b]之间的点的权值之和,可以将查询分为[1,a-1]和[1,b],前者的贡献为负,后者的贡献为正;
②对于修改操作val[x]->y,可以看成先把权值减去val[x],再把权值加上y(注意能直接加上-val[x],因为cdq分治中需要按照val排序,val为负时这个操作就没有意义了,因为这个操作即会影响贡献为负的查询也会影响贡献为正的查询);因为树上一开始就有权值,因此可以看成n次权值0->val[u]的修改权值的操作。

此题还可以用树套树求解,解题报告戳这里

#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);
}


struct Tree {
    LL a[MX];
    int n;
    void init (int _n) {
        n = _n;
        for (int i = 0; i <= n; i++) a[i] = 0;
    }
    void add (int x, int v) {
        for (int i = x; i <= n; i += i & -i) a[i] += v;
    }
    LL sum (int x) {
        LL ret = 0;
        for (int i = x; i > 0; i -= i & -i) ret += a[i];
        return ret;
    }
    LL query (int l, int r) {
        return sum (r) - sum (l - 1);
    }
} T;


struct Que {
    int op, u, v, t, x, id;
} q[MX * 3], tmp[MX * 3];
int val[MX], mark[MX];
LL ans[MX];
bool cmp (const Que& q1, const Que& q2) {
    if (q1.id != q2.id) return q1.id < q2.id;
    return q1.t < q2.t;
}

void cdq (int l, int r) {
    if (l >= r) return;
    int m = (l + r) >> 1, p1 = l, p2 = m + 1, i = 0;
    cdq (l, m); cdq (m + 1, r);
    int op, u, v, t, x, id;
    int mark = 0;
    if (l == 6 && r == 9) mark = 1;
    while (p1 <= m || p2 <= r) {
        if (p1 <= m && (p2 > r || q[p1].t <= q[p2].t) ) {
            op = q[p1].op, u = q[p1].u, v = q[p1].v, t = q[p1].t, x = q[p1].x, id = q[p1].id;
            tmp[i++] = q[p1++];
            if (op == 2) T.add (p[x], v * t);
        } else {
            op = q[p2].op, u = q[p2].u, v = q[p2].v, t = q[p2].t, x = q[p2].x, id = q[p2].id;
            tmp[i++] = q[p2++];
            if (op == 1) {
                LL &cnt = ans[id];
                int f1 = top[u], f2 = top[v];
                while (f1 != f2) {
                    if (dep[f1] < dep[f2]) {
                        swap (u, v);
                        swap (f1, f2);
                    }
                    cnt += x * T.query (p[f1], p[u]);
                    u = f[f1], f1 = top[u];
                }
                if (dep[u] > dep[v]) swap (u, v);
                cnt += x * T.query (p[u], p[v]);
            }
        }
    }
    for (int j = l; j <= m; j++) if (q[j].op == 2) T.add (p[q[j].x], -q[j].v * q[j].t);
    for (int j = 0; j < i; j++) q[l + j] = tmp[j];
}

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) ) {
        init();
        for (int i = 1; i <= n; i++) scanf ("%d", &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);

        int cnt = 0;
        for (int i = 1; i <= n; i++) {
            q[++cnt] = (Que) {2, 0, 1, val[i], i, 0};
        }
        for (int i = 1; i <= m; i++) {
            scanf ("%s", op);
            if (op[0] == 'Q') {
                scanf ("%d%d%d%d", &u, &v, &a, &b);
                q[++cnt] = (Que) {1, u, v, a - 1, -1, i};
                q[++cnt] = (Que) {1, u, v, b, 1, i};
                mark[i] = 1;
            } else {
                scanf ("%d%d", &x, &y);
                q[++cnt] = (Que) {2, 0, 1, y, x, i};
                q[++cnt] = (Que) {2, 0, -1, val[x], x, i};
                //printf("[%d]\n",-val[x]);
                val[x] = y;
                mark[i] = 0;
            }
        }
        sort (q + 1, q + cnt + 1, cmp);
        T.init (n);
        for (int i = 1; i <= m; i++) ans[i] = 0;
        cdq (1, cnt);
        for (int i = 1; i <= m; i++) {
            if (mark[i]) printf ("%lld\n", ans[i]);
        }
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_31759205/article/details/80567445
今日推荐