洛谷P4074 [WC2013]糖果公园(莫队)
总算会树形莫队了……
上次听说树形莫队是给树分块,实在看不懂。然后用括号序列的方法做总算能弄明白了
先说一下什么是括号序列,就是在$dfs$的时候,进入的时候记录一下,出去的时候也记录一下
拿样例为例,它的括号序列就是$12443321$
那么我们扩展区间对答案的贡献是可以$O(1)$计算的
假设扩展出的点的颜色是$c$,那么变化量为$val_c*worth_{cnt_c+1}$
因为括号序列它在扩展的时候会把子树里的扫两遍,那么就可以把子树中的答案去掉了
怎么去掉呢?记录一个$vis$然后每次扫到的时候异或一下,看看是否被扫过就行了
然而有几个问题
第一,$LCA$不是路径端点的话不会被记入答案
考虑上面的括号序列,如果要从$4$到$3$那么$2$是不会被计入答案的
第二,起点不是$LCA$的话不会被记入答案
考虑上面,$u$被算了两次,刚好把自己给减掉了
所以上面的两种情况要特判
然后因为是带修莫队,所以再加上时间这一维
还有这题细节挺多的……我因为跳时间轴的时候一个地方写错WA了好久……
1 //minamoto 2 #include<iostream> 3 #include<cstdio> 4 #include<algorithm> 5 #include<cstring> 6 #include<cmath> 7 #define ll long long 8 using namespace std; 9 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 10 char buf[1<<21],*p1=buf,*p2=buf; 11 inline int read(){ 12 #define num ch-'0' 13 char ch;bool flag=0;int res; 14 while(!isdigit(ch=getc())) 15 (ch=='-')&&(flag=true); 16 for(res=num;isdigit(ch=getc());res=res*10+num); 17 (flag)&&(res=-res); 18 #undef num 19 return res; 20 } 21 char sr[1<<21],z[30];int C=-1,Z; 22 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} 23 inline void print(ll x){ 24 if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x; 25 while(z[++Z]=x%10+48,x/=10); 26 while(sr[++C]=z[Z],--Z);sr[++C]='\n'; 27 } 28 const int N=100005; 29 struct query{ 30 int x,y,l,r,id,t; 31 }q[N];int q1; 32 struct change{int x,c;}t[N];int q2; 33 int n,m,L,R,T,s,Q;ll now,ans[N]; 34 int ver[N<<1],edge[N<<1],head[N],Next[N<<1],top[N],dfn[N],dep[N],sz[N],son[N],lis[N<<1],fa[N],tot,num; 35 int vis[N],col[N],wor[N],cnt[N],val[N]; 36 inline bool cmp(const query a,const query b){ 37 if(a.l^b.l) return a.l<b.l; 38 if(a.r^b.r) return a.l&1?a.r<b.r:a.r>b.r; 39 return (a.l^a.r)&1?a.t<b.t:a.t>b.t; 40 } 41 inline void add(int u,int v){ 42 ver[++tot]=v,Next[tot]=head[u],head[u]=tot; 43 ver[++tot]=u,Next[tot]=head[v],head[v]=tot; 44 } 45 void dfs(int u){ 46 dep[u]=dep[fa[u]]+1,sz[u]=1; 47 for(int i=head[u];i;i=Next[i]){ 48 int v=ver[i]; 49 if(v!=fa[u]){ 50 fa[v]=u,dfs(v),sz[u]+=sz[v]; 51 if(sz[v]>sz[son[u]]) son[u]=v; 52 } 53 } 54 } 55 void dfs(int u,int t){ 56 top[u]=t,lis[dfn[u]=++num]=u; 57 if(son[u]) dfs(son[u],t); 58 for(int i=head[u];i;i=Next[i]){ 59 if(ver[i]!=fa[u]&&ver[i]!=son[u]) dfs(ver[i],ver[i]); 60 } 61 lis[++num]=u; 62 } 63 inline int LCA(int u,int v){ 64 while(top[u]!=top[v]){ 65 if(dep[top[u]]<dep[top[v]]) swap(u,v); 66 u=fa[top[u]]; 67 } 68 return dep[u]<dep[v]?u:v; 69 } 70 inline void sol(int x){ 71 int c=col[x]; 72 (vis[x]^=1)?now+=(ll)wor[++cnt[c]]*val[c]:now-=(ll)wor[cnt[c]--]*val[c]; 73 } 74 inline void mdy(int i){ 75 int u=t[i].x,x=t[i].c,y=col[u]; 76 if(vis[u]) now+=(ll)wor[++cnt[x]]*val[x]-(ll)wor[cnt[y]--]*val[y]; 77 t[i].c=y,col[u]=x; 78 } 79 int main(){ 80 n=read(),m=read(),Q=read(); 81 for(int i=1;i<=m;++i) val[i]=read(); 82 for(int i=1;i<=n;++i) wor[i]=read(); 83 for(int i=1;i<n;++i){ 84 int u=read(),v=read();add(u,v); 85 } 86 for(int i=1;i<=n;++i) col[i]=read(); 87 dfs(1),dfs(1,1); 88 while(Q--){ 89 int opt=read(),x=read(),y=read(); 90 if(opt){if(dfn[x]>dfn[y]) swap(x,y); 91 q[++q1]=(query){x,y,dfn[x],dfn[y],q1,q2}; 92 } 93 else t[++q2]=(change){x,y}; 94 } 95 s=pow(n,q2?2.0/3:1.0/2); 96 for(int i=1;i<=n;++i) q[i].l/=s,q[i].r/=s; 97 sort(q+1,q+1+q1,cmp),L=dfn[q[1].l],R=L-1,T=0; 98 for(int i=1;i<=q1;++i){ 99 int u=q[i].x,v=q[i].y; 100 int l=dfn[u],r=dfn[v],g=q[i].t; 101 while(L>l) sol(lis[--L]); 102 while(R<r) sol(lis[++R]); 103 while(L<l) sol(lis[L++]); 104 while(R>r) sol(lis[R--]); 105 while(T<g) mdy(++T); 106 while(T>g) mdy(T--); 107 //LCA不是路径端点的话是不会计算的 108 //出发点u如果不是LCA也是不会计算的 109 //这两个都要特判 110 int p=LCA(u,v); 111 if(u!=p){sol(u);if(v!=p) sol(p);} 112 ans[q[i].id]=now; 113 if(u!=p){sol(u);if(v!=p) sol(p);} 114 } 115 for(int i=1;i<=q1;++i) print(ans[i]); 116 Ot(); 117 return 0; 118 }
深深地明白自己的弱小