WC2013 糖果公园

树上每个点有颜色,每个颜色有一个关于出现次数的权值,定义一条路径的权值为 $sum$ 路径上每个点权值 $ imes$ 它的颜色在路径上出现次数的权值

给 $q$ 次操作,每次修改一个点的颜色或者询问一条路径的权值

$n leq 100000$

sol:

bzoj 200s 极度酸爽

只被我卡了一个人,极度差评

这题如果没有单点修改,是一个树上莫队题,如果有单点修改,就是一个树上带修改莫队题

于是都来写一写:

树上莫队,首先王室联邦分块,维护一下每个点在不在当前路径上

每次暴力爬 $(c_u,q_u),(c_v,q_v)$ 这两条路径修改,最后单算一下 $LCA(q_u,q_v)$ 的贡献即可

带修改莫队,就是在每个询问操作的时候维护一个时间戳,也维护一个当前时间戳,每次把当前时间戳移动到操作时间戳即可

移动时顺便计算/消除每次修改操作的影响,如果有影响,就直接加上去,然后把修改操作改成反向修改操作

这题把这俩东西整到一起就可以了

这份代码很慢,还有可以卡的地方:O(1) lca,使用欧拉序分块,fread,指令集

#include <bits/stdc++.h>
#define LL long long
#define rep(i, s, t) for (register int i = (s), i##end = (t); i <= i##end; ++i)
#define dwn(i, s, t) for (register int i = (s), i##end = (t); i >= i##end; --i)
using namespace std;
inline int read() {
    int x = 0, f = 1; char ch;
    for (ch = getchar(); !isdigit(ch); ch = getchar()) if (ch == '-') f = -f;
    for (; isdigit(ch); ch = getchar()) x = 10 * x + ch - '0';
    return x * f;
}
const int maxn = 100010;
int n, m, nq, sz, v[maxn], w[maxn], c[maxn];
int first[maxn], to[maxn << 1], nx[maxn << 1], cnt;
inline void add(int u, int v) {
    to[++cnt] = v;
    nx[cnt] = first[u];
    first[u] = cnt;
}
int size[maxn], fa[maxn], top[maxn], dep[maxn];
inline void sp_dfs1(int x) {
    size[x] = 1;
    for(int i=first[x];i;i=nx[i]) {
        if(to[i] == fa[x]) continue;
        fa[to[i]] = x; dep[to[i]] = dep[x] + 1;
        sp_dfs1(to[i]); size[x] += size[to[i]];
    }
}
inline void sp_dfs2(int x, int col) {
    int k = 0; top[x] = col;
    for(int i=first[x];i;i=nx[i])
        if(to[i] != fa[x] && size[to[i]] > size[k]) k = to[i];
    if(!k) return; sp_dfs2(k, col);
    for(int i=first[x];i;i=nx[i])
        if(to[i] != fa[x] && to[i] != k) sp_dfs2(to[i], to[i]);
}
inline int lca(int x, int y) {
    while(top[x] != top[y]) {
        if(dep[top[x]] < dep[top[y]]) swap(x, y);
        x = fa[top[x]];
    }
    return dep[x] < dep[y] ? x : y;
}
int q[maxn], tp, bl[maxn], bcnt;
int fk_dfs(int x) {
    int cur = 0;
    for(int i=first[x];i;i=nx[i]) {
        int v = to[i]; if(v == fa[x]) continue;
        cur += fk_dfs(v);
        if(cur >= sz) {
            bcnt++;
            while(cur--) bl[q[--tp]] = bcnt;
        }
    }
    q[++tp] = x;
    return cur + 1;
}
struct Ques {
    int u, v, fu, fv, id, t;
    Ques(){}
    Ques(int _1, int _2, int _3, int _4, int _5, int _6): u(_1), v(_2), fu(_3), fv(_4), id(_5), t(_6){}
    bool operator < (const Ques &b) const {
        if(fu == b.fu) {
            if(fv == b.fv) return t < b.t;
            return fv < b.fv;
        }return fu < b.fu;
    }
}qs[maxn];
struct Chg {
    int pos, val;
    Chg(){}
    Chg(int _1, int _2): pos(_1), val(_2){}
}cs[maxn];
int pnt[maxn], vis[maxn];
int qcnt, ccnt, iter;
LL ans[maxn], now;
inline void opt(int x) {
    if(vis[x]) {
        now -= 1LL * v[c[x]] * w[pnt[c[x]]];
        pnt[c[x]]--;
    }
    else {
        pnt[c[x]]++;
        now += 1LL * v[c[x]] * w[pnt[c[x]]];
    }
    vis[x] ^= 1;
}
inline void move(int &x) { opt(x); x = fa[x]; }
inline void change(int tim) {
    if(vis[cs[tim].pos]) {
        opt(cs[tim].pos);
        swap(c[cs[tim].pos], cs[tim].val);
        opt(cs[tim].pos);
    }
    else swap(c[cs[tim].pos], cs[tim].val);
}
int main() {
    n = read(), m = read(), nq = read();
    sz = (int)pow(n, 0.6666666666666);
    rep(i, 1, m) v[i] = read(); rep(i, 1, n) w[i] = read();
    rep(i, 2, n) {
        int u = read(), v = read();
        add(u, v); add(v, u);
    }sp_dfs1(1); sp_dfs2(1, 1); fk_dfs(1);
    rep(i, 1, n) c[i] = read();
    rep(i, 1, nq) {
        int opt = read(), x = read(), y = read();
        if(opt == 0) cs[++ccnt] = Chg(x, y);
        if(opt == 1) {
            if(bl[x] > bl[y]) swap(x, y);
            qs[++qcnt] = Ques(x, y, bl[x], bl[y], qcnt, ccnt);
        }
    }
    sort(qs + 1, qs + qcnt + 1);
    while(tp) bl[q[--tp]] = bcnt;
    //rep(i, 1, n) cout << bl[i] << " ";
    //cout << endl;
    int cu = 1, cv = 1;
    //return 0;
    rep(i, 1, qcnt) {
        //cout << iter << " " << qs[i].t << endl;
        while(iter < qs[i].t) change(++iter);
        while(iter > qs[i].t) change(iter--);
        int qu = qs[i].u, qv = qs[i].v;
        int anc = lca(cu, qu);
        while(cu != anc) move(cu); while(qu != anc) move(qu);
        anc = lca(cv, qv);
        while(cv != anc) move(cv); while(qv != anc) move(qv);
        cu = qs[i].u, cv = qs[i].v;
        anc = lca(cu, cv);
        opt(anc); ans[qs[i].id] = now; opt(anc);
        //cout << i << " " << qs[i].id << endl;
    }
    rep(i, 1, qcnt) printf("%lld
", ans[i]);
}
/*
4 3 5
1 9 2
7 6 5 1
2 3
3 1
3 4
1 2 3 2
1 1 2
1 4 2
0 2 1
1 1 2
1 4 2
*/
View Code
原文地址:https://www.cnblogs.com/Kong-Ruo/p/10500675.html