LUOGU P4074 [WC2013]糖果公园

传送门

解题思路

树上带修莫队,搞了两天。。终于开O2+卡常大法贴边过了。。。bzoj上跑了183s。。其实就是把树上莫队和带修莫队结合到一起,首先求出括号序,就是进一次出一次那种的,然后如果求两个点且两个点的LCA是这两个点的一个,那么树上的路径其实就是in[x]到in[y]。如果不是的话就是out[x]到in[y],且要加上lca,但这样太难统计,所以其实可以变成in[x]到in[y],然后直接特判。假如一段序列中既有一个点的in,又有一个点的out,那么其实就相当于没算,所以要记个vis数组表示这个东西该加还是该减,细节超级超级超级多。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<map>

using namespace std;
const int MAXN = 150005;
typedef long long LL;

inline int rd(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();}
    while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return f?x:-x;
}

inline void write(LL x){
    if(x>9) write(x/10);
    putchar(x%10+'0');
}

int n,m,Q,v[MAXN],w[MAXN],tot,head[MAXN],bl[MAXN],Qnum;
int to[MAXN<<1],nxt[MAXN<<1],candy[MAXN],sizz,Qcnt,Ccnt;
int in[MAXN],out[MAXN],node[MAXN<<1],num,cnt[MAXN];
int fa[MAXN],son[MAXN],siz[MAXN],dep[MAXN],top[MAXN];
LL ans[MAXN],Ans;
bool vis[MAXN];
map<pair<int,int>,int> mp;

struct Data{
    int l,r,id,pre,lca;
}q[MAXN];

struct Change{
    int pos,val;
}c[MAXN];

inline void add(int bg,int ed){
    to[++tot]=ed,nxt[tot]=head[bg],head[bg]=tot;
}

void dfs1(int x,int f,int d){
    fa[x]=f,dep[x]=d,siz[x]=1;
    in[x]=++num,node[num]=x;
    register int maxson=-1,u;
    for(register int i=head[x];i;i=nxt[i]){
        u=to[i];if(u==f) continue;
        dfs1(u,x,d+1);
        siz[x]+=siz[u];
        if(siz[u]>maxson) {maxson=siz[u];son[x]=u;}
    }
    out[x]=++num,node[num]=x;
}

void dfs2(int x,int topf){
    top[x]=topf;
    if(!son[x]) return;
    dfs2(son[x],topf);register int u;
    for(register int i=head[x];i;i=nxt[i]){
        u=to[i];if(u==son[x] || u==fa[x]) continue;
        dfs2(u,u); 
    }
}

inline int LCA(int x,int y){
    while(top[x]!=top[y]){
        if(dep[top[x]]>=dep[top[y]]) x=fa[top[x]];
        else y=fa[top[y]];
    }
    return dep[x]>dep[y]?y:x;
}

inline bool cmp(Data A,Data B){
    if(bl[A.l]!=bl[B.l]) return bl[A.l]<bl[B.l];
    if(bl[A.r]!=bl[B.r]) return bl[A.r]<bl[B.r];
    return A.pre<B.pre;
}

inline void Add(int x){
    if(!vis[node[x]]){
        vis[node[x]]^=1;
        cnt[candy[node[x]]]++;
        Ans+=(LL)w[cnt[candy[node[x]]]]*v[candy[node[x]]];
//        cout<<Ans<<endl;    
    }
    else {
        vis[node[x]]^=1;
        Ans-=(LL)w[cnt[candy[node[x]]]]*v[candy[node[x]]];
        cnt[candy[node[x]]]--;
    }
}

inline void Work(int x){
    if(vis[node[c[x].pos]]) {
        Ans-=(LL)w[cnt[candy[node[c[x].pos]]]]*v[candy[node[c[x].pos]]];
        cnt[candy[node[c[x].pos]]]--;cnt[c[x].val]++;
        Ans+=(LL)w[cnt[c[x].val]]*v[c[x].val];
    }     
    swap(c[x].val,candy[node[c[x].pos]]);
}

int main(){
    n=rd(),m=rd(),Q=rd();
    for(register int i=1;i<=m;i++) v[i]=rd();
    for(register int i=1;i<=n;i++) w[i]=rd();
    register int x,y,opt;
    for(register int i=1;i<n;i++){
        x=rd(),y=rd();
        add(x,y),add(y,x);
    }
    for(register int i=1;i<=n;i++) candy[i]=rd();
    dfs1(1,0,0);dfs2(1,1);register int Lca;
    for(register int i=1;i<=Q;i++){
        opt=rd(),x=rd(),y=rd();
        if(opt==1){
            if(mp.count(make_pair(x,y))) Lca=mp[make_pair(x,y)];
            else {Lca=LCA(x,y);mp[make_pair(x,y)]=mp[make_pair(y,x)]=Lca;}
            if(in[x]>in[y]) swap(x,y);
            q[++Qcnt].l=in[x],q[Qcnt].r=in[y],q[Qcnt].id=Qcnt,q[Qcnt].pre=Ccnt,q[Qcnt].lca=in[Lca];
        }
        else {c[++Ccnt].pos=in[x];c[Ccnt].val=y;}
    }
    sizz=pow(n,Ccnt?0.6:0.5);
    for(register int i=1;i<=n;i++) bl[i]=i/sizz+1;
//    for(int i=1;i<=Qcnt;i++) cout<<q[i].l<<" "<<q[i].r<<endl;
    sort(q+1,q+1+Qcnt,cmp);
//    for(int i=1;i<=Qcnt;i++) cout<<q[i].l<<" "<<q[i].r<<" "<<q[i].id<<endl;
    register int L=q[1].l,R=q[1].l-1,now=0;
    for(register int i=1;i<=Qcnt;i++){
        while(L<q[i].l) {Add(L);L++;}
        while(L>q[i].l) {L--;Add(L);}
        while(R<q[i].r) {R++;Add(R);}
        while(R>q[i].r) {Add(R);R--;}
        while(now<q[i].pre) {now++;Work(now);}
        while(now>q[i].pre) {Work(now);now--;}
        if(q[i].lca!=q[i].l) Add(q[i].l);
        if(q[i].lca!=q[i].l && q[i].lca!=q[i].r) Add(q[i].lca);
        ans[q[i].id]=Ans;
        if(q[i].lca!=q[i].l) Add(q[i].l);
        if(q[i].lca!=q[i].l && q[i].lca!=q[i].r) Add(q[i].lca);
    }
    for(register int i=1;i<=Qcnt;i++) write(ans[i]),puts("");
    return 0;
}

/*
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

0 2 1
1 1 2
1 4 2
*/
View Code

猜你喜欢

转载自www.cnblogs.com/sdfzsyq/p/9691516.html