解题思路
树上带修莫队,搞了两天。。终于开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 */