[BZOJ3531]旅行

题目链接BZOJ3551

题目大意
维护一棵树,树上每个点两个权值 C W,要求支持三个操作:( N,C1e5 )
1. CC i X ,修改点 i 的权值Ci X
2. CW i X,修改点 i 的权值Wi X
3. QS i j(保证 Ci=Cj ),求 xACx=CiWx ,其中A为从i到j的路径上点的集合(包括 i j);
4. QM i j (保证 Ci=Cj ),求 maxxACx=CiWx ,其中A为从i到j的路径上点的集合(包括 i j)。

题目分析
1. 首先有个显然的做法:维护 C 棵线段树,C权为 X 的在第X棵线段树中的权值为其 W 权值,在其他线段树中为0,然而会MLE;
2. 对于树上每个点,只会存在于一颗线段树上,于是我们可以动态开点回收;
3. 当一个点从一颗线段树转移到另一颗线段树时,从原线段树上删掉它,并在新线段树上添加;
4. 对于线段树上的某个点,如果它对应的区间里面一个点都没有,那么这个点也可以删掉,这样的话所有点的数量就是 NlogN 啦。

上代码

#include <stack>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int N = 1e5 + 10;
const int M = 2e6 + 10;

int n, q;
inline int read() {
    char ch;
    int ans = 0, neg = 1;
    while (!isdigit(ch = getchar()))
        if (ch == '-') neg = -1;
    while (isdigit(ch))
        ans = ans * 10 + ch - '0', ch = getchar();
    return ans * neg;
}

int rel[N], val[N];
vector <int> edge[N];

namespace HLD {
    int fa[N], son[N], dep[N], size[N];
    int top[N], plc[N], replc[N], cntSeg;
    void dfs1(int a, int par) {
        dep[a] = dep[fa[a] = par] + (size[a] = 1);
        for (int i = 0; i < edge[a].size(); i++) {
            int cur = edge[a][i];
            if (cur == par) continue;
            dfs1(cur, a), size[a] += size[cur];
            if (size[cur] > size[son[a]]) son[a] = cur;
        }
    }
    void dfs2(int a, int up) {
        top[a] = up, replc[plc[a] = ++cntSeg] = a;
        if (son[a]) dfs2(son[a], up);
        for (int i = 0; i < edge[a].size(); i++) {
            int cur = edge[a][i];
            if (cur == fa[a] || cur == son[a]) continue;
            dfs2(cur, cur);
        }
    }

    int cnt = 1e5;
    stack <int> bin;
    int lc[M], rc[M], lp[M], rp[M];
    int tot[M], maxn[M];
    #define isRoot(a) (lp[a] == 1 && rp[a] == n)
    inline int getNew(int l, int r) {
        int tmp = 0;
        if (bin.empty()) tmp = ++cnt;
        else tmp = bin.top(), bin.pop();
        tot[tmp] = maxn[tmp] = 0;
        lc[tmp] = rc[tmp] = 0, lp[tmp] = l, rp[tmp] = r;
        return tmp;
    }
    void build() {
        for (int i = 1; i <= cnt; i++)
            lp[i] = 1, rp[i] = n;
    }
    inline void pushUp(int a) {
        tot[a] = tot[lc[a]] + tot[rc[a]];
        maxn[a] = max(maxn[lc[a]], maxn[rc[a]]);
    }
    void add(int a, int p) {
        if (lp[a] == rp[a])
            return tot[a] = maxn[a] = val[replc[p]], void(0);
        int mid = (lp[a] + rp[a]) >> 1;
        if (p <= mid) {
            if (!lc[a]) lc[a] = getNew(lp[a], mid);
            add(lc[a], p);
        } else {
            if (!rc[a]) rc[a] = getNew(mid + 1, rp[a]);
            add(rc[a], p);
        } pushUp(a);
    }
    bool delett(int a, int p) {
        if (lp[a] == rp[a])
            return bin.push(a), true;
        int mid = (lp[a] + rp[a]) >> 1;
        if (p <= mid && delett(lc[a], p) && (lc[a] = 0, !rc[a]) && !isRoot(a))
            return bin.push(a), true;
        else if (p > mid && delett(rc[a], p) && (rc[a] = 0, !lc[a]) && !isRoot(a))
            return bin.push(a), true;
        return pushUp(a), false;
    }
    void modify(int a, int p) {
        if (lp[a] == p && rp[a] == p)
            return tot[a] = maxn[a] = val[replc[p]], void(0);
        int mid = (lp[a] + rp[a]) >> 1;
        if (p <= mid) modify(lc[a], p);
        else modify(rc[a], p);
        pushUp(a);
    }
    int queryMax(int a, int l, int r) {
        if (a == 0) return 0;
        if (lp[a] == l && rp[a] == r)
            return maxn[a];
        int mid = (lp[a] + rp[a]) >> 1;
        if (r <= mid) return queryMax(lc[a], l, r);
        else if (l > mid) return queryMax(rc[a], l, r);
        else return max(queryMax(lc[a], l, mid), queryMax(rc[a], mid + 1, r));
    }
    int queryTot(int a, int l, int r) {
        if (a == 0) return 0;
        if (lp[a] == l && rp[a] == r)
            return tot[a];
        int mid = (lp[a] + rp[a]) >> 1;
        if (r <= mid) return queryTot(lc[a], l, r);
        else if (l > mid) return queryTot(rc[a], l, r);
        else return queryTot(lc[a], l, mid) + queryTot(rc[a], mid + 1, r);
    }
    int decomMax(int s, int a, int b) {
        int ans = 0;
        while (top[a] != top[b]) {
            if (dep[top[a]] < dep[top[b]]) swap(a, b);
            ans = max(ans, queryMax(s, plc[top[a]], plc[a]));
            a = fa[top[a]];
        }
        if (dep[a] < dep[b]) swap(a, b);
        ans = max(ans, queryMax(s, plc[b], plc[a]));
        return ans;
    }
    int decomTot(int s, int a, int b) {
        int ans = 0;
        while (top[a] != top[b]) {
            if (dep[top[a]] < dep[top[b]]) swap(a, b);
            ans += queryTot(s, plc[top[a]], plc[a]);
            a = fa[top[a]];
        }
        if (dep[a] < dep[b]) swap(a, b);
        ans += queryTot(s, plc[b], plc[a]);
        return ans;
    }
}

void init() {
    n = read(), q = read();
    for (int i = 1; i <= n; i++)
    val[i] = read(), rel[i] = read();
    for (int i = 1; i < n; i++) {
        int a = read(), b = read();
        edge[a].push_back(b), edge[b].push_back(a);
    }
    HLD::dfs1(1, 0), HLD::dfs2(1, 1), HLD::build();
    for (int i = 1; i <= n; i++)
        HLD::add(rel[i], HLD::plc[i]);
}
void figure() {
    char ss[5]; int a, b;
    for (int i = 1; i <= q; i++) {
        scanf("%s", ss), a = read(), b = read();
        if (ss[1] == 'C') {
            HLD::delett(rel[a], HLD::plc[a]);
            HLD::add(rel[a] = b, HLD::plc[a]);
        } else if (ss[1] == 'W') {
            val[a] = b;
            HLD::modify(rel[a], HLD::plc[a]);
        } else if (ss[1] == 'S')
            printf("%d\n", HLD::decomTot(rel[a], a, b));
        else if (ss[1] == 'M')
            printf("%d\n", HLD::decomMax(rel[a], a, b));
    }
}

int main() {
    init();
    figure();
    return 0;
}

以上

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值