治好了個人樹上莫隊/帶修莫隊恐懼症……c++
對樹的分塊要求塊內的元素都聯通,能夠參考[SCOI 2005]王室聯邦的分塊作法。對於路徑的修改,若已經存在x-y的路徑,要轉化到X-Y的路徑(此處所言路徑不包含兩點的lca),能夠發現路徑X-Y等於路徑x-y、路徑X-x、路徑Y-y這三者的對稱差(異或?),最後在臨時計入點lca(X,Y)便可。spa
而後時模擬時間(修改顏色、撤銷修改),當塊大小爲n^{2/3}時複雜度最優爲O(n^{5/3}),(認爲q與n同階)。code
#include <bits/stdc++.h> #define ll long long using namespace std; const int N=1e5+10; int n,m,Q,ccnt,qcnt; int ehd[N],to[N<<1],lst[N<<1],fa[N][20],dep[N]; int top,tot,B,bl[N],stk[N],a[N],V[N],W[N],num[N]; ll ans,out[N]; bool vis[N]; struct TimeCh {int p,x;} c[N]; struct PathCh { int x,y,t,id; bool operator<(const PathCh&d) const { if(bl[x]!=bl[d.x]) return bl[x]<bl[d.x]; if(bl[y]!=bl[d.y]) return bl[y]<bl[d.y]; return t<d.t; } } q[N]; void insert(int x,int y) { static int cnt=0; to[++cnt]=y,lst[cnt]=ehd[x],ehd[x]=cnt; to[++cnt]=x,lst[cnt]=ehd[y],ehd[y]=cnt; } void dfs(int x) { int pre=top; for(int i=1; (1<<i)<=dep[x]; ++i) fa[x][i]=fa[fa[x][i-1]][i-1]; for(int i=ehd[x]; i; i=lst[i]) if(to[i]!=fa[x][0]) { int y=to[i]; dep[y]=dep[fa[y][0]=x]+1; dfs(y); if(top-pre>=B) { tot++; do bl[stk[top--]]=tot; while(top!=pre); } } stk[++top]=x; } int lca(int x,int y) { if(dep[x]<dep[y]) swap(x,y); int dif=dep[x]-dep[y]; for(int i=19; ~i; --i) if((dif>>i)&1) x=fa[x][i]; if(x==y) return x; for(int i=19; ~i; --i) if(fa[x][i]^fa[y][i]) x=fa[x][i],y=fa[y][i]; return fa[x][0]; } void point(int p) { if(vis[p]) ans-=1LL*V[a[p]]*W[num[a[p]]--]; else ans+=1LL*V[a[p]]*W[++num[a[p]]]; vis[p]^=1; } void time(int t) { if(vis[c[t].p]) point(c[t].p),swap(c[t].x,a[c[t].p]),point(c[t].p); else swap(c[t].x,a[c[t].p]); } void path(int x,int y) { if(dep[x]<dep[y]) swap(x,y); while(dep[x]>dep[y]) point(x),x=fa[x][0]; while(x!=y) point(x),point(y),x=fa[x][0],y=fa[y][0]; //去掉lca } int main() { scanf("%d%d%d",&n,&m,&Q); B=pow(n,0.66); for(int i=1; i<=m; ++i) scanf("%d",V+i); for(int i=1; i<=n; ++i) scanf("%d",W+i); for(int x,y,i=n; --i; ) scanf("%d%d",&x,&y),insert(x,y); for(dfs(1); top; ) bl[stk[top--]]=tot; for(int i=1; i<=n; ++i) scanf("%d",a+i); for(int type,i=Q; i--; ) { scanf("%d",&type); if(type==0) { ccnt++; scanf("%d%d",&c[ccnt].p,&c[ccnt].x); } else { scanf("%d%d",&q[qcnt].x,&q[qcnt].y); q[qcnt].t=ccnt; q[qcnt].id=qcnt; qcnt++; } } sort(q,q+qcnt); int x=1,y=1,now=0; for(int i=0; i<qcnt; ++i) { path(x,q[i].x); x=q[i].x; path(y,q[i].y); y=q[i].y; while(now<q[i].t) time(++now); while(now>q[i].t) time(now--); int d=lca(x,y); point(d); out[q[i].id]=ans; point(d); } for(int i=0; i<qcnt; ++i) printf("%lld\n",out[i]); return 0; }