【BZOJ 3052】糖果公园

题目来源:BZOJ 3052 UOJ 58

思路:

把树转化为欧拉序,把询问映射到欧拉序上,在欧拉序上跑带修改莫队。
具体的做法可以参考<国家集训队2014论文集.pdf>的第82页描述的性质。

<国家集训队2014论文集.pdf> 6.3M 百度云链接 密码: p4n2

代码:

#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 200010;
int n, m, qq, uu, vv, qcnt, tmp, ccnt, dcnt, blsz, l, r, tm;
int c[maxn], bl[maxn];
int ne[maxn], po[maxn], fa[maxn], dep[maxn], sz[maxn], dfn[maxn*2];
int son[maxn], top[maxn], in[maxn], out[maxn], vnum[maxn];
long long ans[maxn], res, v[maxn], w[maxn];
vector <int> head[maxn];
bool is[maxn];
struct node{int l, r, id, lca, time;}q[maxn];
inline bool cmp(const node a, const node b){
    if(bl[a.l] == bl[b.l]){
        if(bl[a.r] == bl[b.r]) return a.time < b.time;
        else return bl[a.r] < bl[b.r];
    }else return bl[a.l] < bl[b.l];
}
inline int gt(){
    char c = ' '; int num = 0, ok = 0;
    while(1){
        c = getchar();
        if(c <= '9' && c >= '0') num = num*10+c-'0', ok = 1;
        else if(ok) return num;
    }
}
void dfs1(int x){
    dfn[in[x] = ++dcnt] = x, sz[x] = 1; int SZ = 0, SZnum = 0;
    for(int i = 0; i < head[x].size(); i ++){
        int u = head[x][i]; if(u == fa[x]) continue;
        fa[u] = x, dep[u] = dep[x] + 1;
        dfs1(u); sz[x] += sz[u];
        if(sz[u] > SZ) SZ = sz[u], SZnum = u;
    } son[x] = SZnum;
    dfn[out[x] = ++dcnt] = x;
}
void dfs2(int x, int tp){
    top[x] = tp;
    if(son[x] != 0) dfs2(son[x], tp);
    for(int i = 0; i < head[x].size(); i ++){
        int u = head[x][i];
        if(u == fa[x] || u == son[x]) continue;
        dfs2(u, u);
    }
}
int lca(int u, int v){
    while(top[u] != top[v])
        dep[top[u]] > dep[top[v]] ? u = fa[top[u]] : v = fa[top[v]];
    return dep[u] < dep[v] ? u : v;
}
void add(int x){
    vnum[c[x]] ++;
    res += w[vnum[c[x]]] * v[c[x]];
}
void del(int x){
    res -= w[vnum[c[x]]] * v[c[x]];
    vnum[c[x]] --;
}
void Xor(int x){
    if(is[x]) del(x);
    else add(x);
    is[x] ^= 1;
}
int main(){
    n = gt(), m = gt(), qq = gt();
    for(int i = 1; i <= m; i ++) v[i] = gt();
    for(int i = 1; i <= n; i ++) w[i] = gt();
    for(int i = 1; i < n; i ++){
        uu = gt(), vv = gt();
        head[uu].push_back(vv);
        head[vv].push_back(uu);
    } dfs1(1), dfs2(1, 1);
    blsz = max(1.0, pow(dcnt, 2.0/3));
    for(int i = 1; i <= dcnt; i ++) bl[i] = (i-1)/blsz + 1;
    for(int i = 1; i <= n; i ++) c[i] = gt();
    for(int i = 1; i <= qq; i ++){
        tmp = gt();
        if(tmp){
            q[++qcnt].l = gt(), q[qcnt].r = gt();
            q[qcnt].lca = lca(q[qcnt].l, q[qcnt].r);
            if(in[q[qcnt].l] > in[q[qcnt].r]) swap(q[qcnt].l, q[qcnt].r);
            if(q[qcnt].lca == q[qcnt].l){
                q[qcnt].l = in[q[qcnt].l], q[qcnt].r = in[q[qcnt].r];
                q[qcnt].lca = 0;
            }else{
                if(out[q[qcnt].l] > in[q[qcnt].r]) swap(q[qcnt].l, q[qcnt].r);
                q[qcnt].l = out[q[qcnt].l], q[qcnt].r = in[q[qcnt].r];
            }
            q[qcnt].id = qcnt, q[qcnt].time = ccnt;
        }else po[++ccnt] = gt(), ne[ccnt] = gt();
    }
    sort(q+1, q+1+qcnt, cmp);
    l = 1, r = 0, tm = 0;
    for(int i = 1; i <= qcnt; i ++){
        for( ; tm < q[i].time; tm ++){
            if((in[po[tm+1]] <= r && in[po[tm+1]] >= l)^
            (out[po[tm+1]] <= r && out[po[tm+1]] >= l)){
                res -= w[vnum[c[po[tm+1]]]]*v[c[po[tm+1]]];
                vnum[c[po[tm+1]]] --;
            }
            swap(c[po[tm+1]], ne[tm+1]);
            if((in[po[tm+1]] <= r && in[po[tm+1]] >= l)^
            (out[po[tm+1]] <= r && out[po[tm+1]] >= l)){
                vnum[c[po[tm+1]]] ++;
                res += w[vnum[c[po[tm+1]]]]*v[c[po[tm+1]]];
            }
        } 
        for( ; tm > q[i].time; tm --){

            if((in[po[tm]] <= r && in[po[tm]] >= l)^
            (out[po[tm]] <= r && out[po[tm]] >= l)){
                res -= w[vnum[c[po[tm]]]]*v[c[po[tm]]];
                vnum[c[po[tm]]] --;
            }
            swap(c[po[tm]], ne[tm]);
            if((in[po[tm]] <= r && in[po[tm]] >= l)^
            (out[po[tm]] <= r && out[po[tm]] >= l)){
                vnum[c[po[tm]]] ++;
                res += w[vnum[c[po[tm]]]]*v[c[po[tm]]];
            }

        }
        for( ; l > q[i].l; l --) Xor(dfn[l-1]);
        for( ; r < q[i].r; r ++) Xor(dfn[r+1]);
        for( ; l < q[i].l; l ++) Xor(dfn[l]);
        for( ; r > q[i].r; r --) Xor(dfn[r]);
        if(q[i].lca != 0){
            add(q[i].lca);
            ans[q[i].id] = res;
            del(q[i].lca);
        }else ans[q[i].id] = res;
    }
    for(int i = 1; i <= qcnt; i ++) printf("%lld\n", ans[i]); 
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值