1. 程式人生 > >洛谷P4074 [WC2013]糖果公園(莫隊)

洛谷P4074 [WC2013]糖果公園(莫隊)

自己 val 分塊 () lis long spa col flag

傳送門

總算會樹形莫隊了……

上次聽說樹形莫隊是給樹分塊,實在看不懂。然後用括號序列的方法做總算能弄明白了

先說一下什麽是括號序列,就是在$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 }

洛谷P4074 [WC2013]糖果公園(莫隊)