【知识点】莫队
莫队:
离线后通过对询问合理排序使得复杂度降低一个$\sqrt{n}$。(本身并不需要用块维护东西)
一般情况下分块大小为$\sqrt{n}$,以左端点所在块为第一关键字,右端点为第二关键字排序。
然后依次暴力处理询问即可。
带修莫队:
一般情况下分块大小为$n^{\frac{2}{3}}$,以左端点所在块为第一关键字,右端点所在块为第二关键字,该询问之前的修改数为第三关键字排序。
然后依次暴力处理询问和修改即可。
树上莫队:
一般情况下用欧拉序把树转成括号序列。(每个点第一次dfs到时加入,最后一次dfs回溯时加入)
然后当成序列做,把加入/删除改成xor即可。
代码(WC2013糖果公园):
#include<bits/stdc++.h> #define maxn 500005 #define maxm 500005 #define inf 0x7fffffff #define ll long long #define rint register ll #define debug(x) cerr<<#x<<": "<<x<<endl #define fgx cerr<<"--------------"<<endl #define dgx cerr<<"=============="<<endl using namespace std; ll V[maxn],W[maxn],A[maxn],B[maxn],C[maxn]; ll nxt[maxn<<1],to[maxn<<1],hd[maxn]; ll F[maxn][20],tC[maxn],E[maxn],tot; ll dep[maxn],st[maxn],ed[maxn],totu; ll vis[maxn],num[maxn],ans,cnt,siz; struct node{ll l,r,val,id,res;}Q[maxn],U[maxn]; inline ll read(){ ll x=0,f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } inline void addedge(ll u,ll v){ to[++cnt]=v,nxt[cnt]=hd[u],hd[u]=cnt; to[++cnt]=u,nxt[cnt]=hd[v],hd[v]=cnt; } inline void dfs(ll u,ll fa){ E[++E[0]]=u,st[u]=E[0]; dep[u]=dep[fa]+1,F[u][0]=fa; for(ll i=1;i<20;i++) F[u][i]=F[F[u][i-1]][i-1]; for(ll i=hd[u];i;i=nxt[i]){ ll v=to[i]; if(v!=fa) dfs(v,u); } E[++E[0]]=u,ed[u]=E[0]; } inline bool cmp(node a,node b){ if(a.l/siz==b.l/siz && a.r/siz==b.r/siz) return a.val<b.val; else if(a.l/siz==b.l/siz) return a.r/siz<b.r/siz; else return a.l/siz<b.l/siz; } inline bool cmp1(node a,node b){return a.id<b.id;} inline ll lca(ll x,ll y){ if(dep[x]>dep[y]) swap(x,y); for(ll i=19;i>=0;i--) if(dep[F[y][i]]>=dep[x]) y=F[y][i]; if(x==y) return x; for(ll i=19;i>=0;i--) if(F[x][i]!=F[y][i]) x=F[x][i],y=F[y][i]; return F[x][0]; } inline void upd(ll u){ vis[u]^=1; if(vis[u]) ans+=W[++num[C[u]]]*V[C[u]]; else ans-=W[num[C[u]]--]*V[C[u]]; } int main(){ ll n=read(),m=read(),q=read(); for(ll i=1;i<=m;i++) V[i]=read(); for(ll i=1;i<=n;i++) W[i]=read(); for(ll i=1;i<=n-1;i++){ ll u=read(),v=read(); addedge(u,v); } for(ll i=1;i<=n;i++) tC[i]=C[i]=read(); for(ll i=1;i<=q;i++){ ll typ=read(),x=read(),y=read(); if(typ==0) U[++totu].val=x,U[totu].l=tC[x],U[totu].r=y,tC[x]=y; else Q[++tot].l=x,Q[tot].r=y,Q[tot].val=totu,Q[tot].id=tot,Q[tot].res=0; } dfs(1,0),siz=pow(2.0*n,2.0/3.0); for(ll i=1;i<=tot;i++){ ll x=Q[i].l,y=Q[i].r; if(dep[x]>dep[y]) swap(x,y); if(lca(x,y)==x) Q[i].l=st[x],Q[i].r=st[y]; else{ if(st[x]>st[y]) swap(x,y); Q[i].l=ed[x],Q[i].r=st[y]; } } sort(Q+1,Q+1+tot,cmp); for(ll i=1;i<=tot;i++){ ll l=Q[i-1].l,r=Q[i-1].r,p=Q[i-1].val; ll f1=lca(E[Q[i-1].l],E[Q[i-1].r]); if(f1!=E[Q[i-1].l]) upd(f1); while(p<Q[i].val){ ll j=++p; if(l<=st[U[j].val] && r>=st[U[j].val] && r<ed[U[j].val]) upd(U[j].val); if(l<=ed[U[j].val] && r>=ed[U[j].val] && l>st[U[j].val]) upd(U[j].val); C[U[j].val]=U[j].r; if(l<=st[U[j].val] && r>=st[U[j].val] && r<ed[U[j].val]) upd(U[j].val); if(l<=ed[U[j].val] && r>=ed[U[j].val] && l>st[U[j].val]) upd(U[j].val); } while(p>Q[i].val){ ll j=p--; if(l<=st[U[j].val] && r>=st[U[j].val] && r<ed[U[j].val]) upd(U[j].val); if(l<=ed[U[j].val] && r>=ed[U[j].val] && l>st[U[j].val]) upd(U[j].val); C[U[j].val]=U[j].l; if(l<=st[U[j].val] && r>=st[U[j].val] && r<ed[U[j].val]) upd(U[j].val); if(l<=ed[U[j].val] && r>=ed[U[j].val] && l>st[U[j].val]) upd(U[j].val); } while(l<Q[i].l) upd(E[l++]); while(l>Q[i].l) upd(E[--l]); while(r<Q[i].r) upd(E[++r]); while(r>Q[i].r) upd(E[r--]); ll f2=lca(E[Q[i].l],E[Q[i].r]); if(f2!=E[Q[i].l]) upd(f2); Q[i].res=ans; } sort(Q+1,Q+1+tot,cmp1); for(ll i=1;i<=tot;i++) printf("%lld\n",Q[i].res); return 0; }