[bzoj3052][wc2013]糖果公园【树上莫队】

【题目链接】
  https://www.lydsy.com/JudgeOnline/problem.php?id=3052
【题解】
  首先是树上莫队的一些套路:
  1.如果是查询子树信息,那么可以选择按dfs序进行分块,这样查询的位置一定是一段区间。
  2.如果是查询一条链的信息,那么欧拉序是首选,记进入时间为 i n i , 离开时间为 o u t i ,此时要分两种情况讨论( i n u < i n v ):1). l c a ( u , v ) 不等于 u v ,那么 o u t u i n v 的区间中出现次数为奇数的点以及 l c a 就是答案。2). l c a ( u , v ) = u ,那么 i n u + 1 i n v 的区间中出现次数为奇数的点以及 l c a 就是答案。
  通过这样的转换,链上问题也能变成区间问题。
  接下来是修改,记每块的大小为 n 2 / 3 ,以左端点所在块为第一关键字,右端点所在块为第二关键字,时间为第三关键字排序,然后转移时暴力修改就行了。可以证明这样做的时间复杂度是 O ( N 5 / 3 )
【代码】

/* - - - - - - - - - - - - - - -
    User :      VanishD
    problem :   [bzoj3052]
    Points :    Mo's algorithm on tree with modification
- - - - - - - - - - - - - - - */
# include <bits/stdc++.h>
# define    ll      long long
# define    inf     0x3f3f3f3f
# define    N       200010
# define    K       20
using namespace std;
int read(){
    int tmp = 0, fh = 1; char ch = getchar();
    while (ch < '0' || ch > '9'){ if (ch == '-') fh = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9'){ tmp = tmp * 10 + ch - '0'; ch = getchar(); }
    return tmp * fh;
}
struct Node{
    int l, r, lca, ti, id;
}qy[N];
struct Edge{
    int data, next;
}e[N * 2];
int out[N], in[N], p[N], n, m, q, v[N], head[N], place, chid[N], chto[N], chlas[N], now[N], c[N], dep[N], dad[N][K + 1], hav[N], ti, size, cnt[N];
ll ans[N], w[N], sum;
void build(int u, int v){
    e[++place].data = v; e[place].next = head[u]; head[u] = place;
}
void dfs(int x, int fa){
    in[x] = ++ti, p[ti] = x; dad[x][0] = fa; dep[x] = dep[fa] + 1;
    for (int ed = head[x]; ed != 0; ed = e[ed].next)
        if (e[ed].data != fa) dfs(e[ed].data, x);
    out[x] = ++ti, p[ti] = x;
}
void pre(){
    for (int i = 1, j = 1; j * 2 <= n; i++, j *= 2)
        for (int k = 1; k <= n; k++)
            dad[k][i] = dad[dad[k][i - 1]][i - 1];
}
int lca(int u, int v){
    if (dep[u] > dep[v]) swap(u, v);
    for (int i = K; i >= 0; i--)
        if (dep[dad[v][i]] >= dep[u]) v = dad[v][i];
    if (u == v) return u;
    for (int i = K; i >= 0; i--)
        if (dad[v][i] != dad[u][i]) 
            v = dad[v][i], u = dad[u][i];
    return dad[v][0];
}
bool cmp(Node x, Node y){
    return (x.l / size < y.l / size) || (x.l / size == y.l / size && x.r / size < y.r / size) || 
        (x.l / size == y.l / size && x.r / size == y.r / size && x.ti < y.ti); 
}
inline void modifysum(int x, int vote){
    sum = sum + w[x] * vote;
}
inline void inc(int x){
    modifysum(cnt[x], -v[x]);
    modifysum(++cnt[x], v[x]);
}
inline void dec(int x){
    modifysum(cnt[x], -v[x]);
    modifysum(--cnt[x], v[x]);
}
void modify(int id){
    if (hav[id] == true)
        dec(now[id]);
        else inc(now[id]);
    hav[id] = hav[id] ^ 1;
}
int main(){
//  freopen("bzoj3052.in", "r", stdin);
//  freopen("bzoj3052.out", "w", stdout);
    n = read(), m = read(), q = read();
    for (int i = 1; i <= m; i++) v[i] = read();
    for (int i = 1; i <= n; i++) w[i] = read() + w[i - 1];
    for (int i = 1; i < n; i++){
        int u = read(), v = read();
        build(u, v); build(v, u);
    }
    for (int i = 1; i <= n; i++) c[i] = now[i] = read();
    dfs(1, 0); pre();
    int qnum = 0, num = 0;
    for (int i = 1; i <= q; i++){
        int op = read();
        if (op == 0){
            chid[++qnum] = read();
            chto[qnum] = read();
            chlas[qnum] = now[chid[qnum]];
            now[chid[qnum]] = chto[qnum];
        }
        else {
            int u = read(), v = read(); 
            qy[++num].ti= qnum; qy[num].id = num;
            if (in[u] > in[v]) swap(u, v);
            int tmp = lca(u, v);
            qy[num].lca = tmp;
            qy[num].r = in[v];
            if (tmp == u)
                qy[num].l = in[u] + 1;
                else  qy[num].l = out[u];
        }
    }
    size = (int)pow(num, 0.67);
    sort(qy + 1, qy + num + 1, cmp);
    int pl = 1, pr = 0, pch = 0; sum = 0;
    for (int i = 1; i <= n; i++) now[i] = c[i];
    for (int i = 1; i <= num; i++){ 
        for (int j = pch + 1; j <= qy[i].ti; j++){
            bool tag = false;
            if (hav[chid[j]] != 0) tag = true;
            if (tag) modify(chid[j]);
            now[chid[j]] = chto[j];
            if (tag) modify(chid[j]);
        }
        for (int j = pch; j > qy[i].ti; j--){
            bool tag = false;
            if (hav[chid[j]] != 0) tag = true;
            if (tag) modify(chid[j]);
            now[chid[j]] = chlas[j];
            if (tag) modify(chid[j]);
        }
        pch = qy[i].ti;
        for (int j = pl - 1; j >= qy[i].l; j--) modify(p[j]);
        for (int j = pr + 1; j <= qy[i].r; j++) modify(p[j]);
        for (int j = pl; j < qy[i].l; j++) modify(p[j]);
        for (int j = pr; j > qy[i].r; j--) modify(p[j]);
        pl = qy[i].l, pr = qy[i].r;
        modify(qy[i].lca);
        ans[qy[i].id] = sum;
        modify(qy[i].lca);
    }
    for (int i = 1; i <= num; i++)
        printf("%lld\n", ans[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/d_vanisher/article/details/80715703