uoj #58. 【WC2013】糖果公园(树上莫队算法+修改操作)
【题目链接】
【题意】
有一棵树,结点有自己的颜色,若干询问:u,v路径上的获益,并提供修改颜色的操作。
其中获益定义为Vc*W1+Vc*W2+…+Vc*Wcnt,cnt为经过颜色c的次数。
【思路】
如果没有修改操作就和 苹果树 这道题一样了。
加上修改操作,我们可以对每一个修改操作打上一个时间戳,并记录每一个查询最后修改的时间戳。这样在莫队“区间移动”的时候,只需要根据时间戳进行时光逆流或顺流,即加上现在时间内前一个时间没有的修改或消除现在时间内没有前一个时间存在的修改。
对于一个修改,如果已经打上标记即这时候计入了now,我们应该先把它在路径上取反存在性,修改后再取反一下就又以新的权值回到了路上,就是重新计算一下贡献。
【代码】
1 #include<set> 2 #include<cmath> 3 #include<queue> 4 #include<vector> 5 #include<cstdio> 6 #include<cstring> 7 #include<iostream> 8 #include<algorithm> 9 #define trav(u,i) for(int i=front[u];i;i=e[i].nxt) 10 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 11 using namespace std; 12 13 typedef long long ll; 14 const int N = 3e5+10; 15 const int D = 21; 16 17 ll read() { 18 char c=getchar(); 19 ll f=1,x=0; 20 while(!isdigit(c)) { 21 if(c=='-') f=-1; c=getchar(); 22 } 23 while(isdigit(c)) 24 x=x*10+c-'0',c=getchar(); 25 return x*f; 26 } 27 28 struct Edge { int v,nxt; 29 }e[N<<2]; 30 int en=1,front[N]; 31 void adde(int u,int v) 32 { 33 e[++en]=(Edge){v,front[u]}; front[u]=en; 34 } 35 36 int n,m,B,Q,dfsc,top,Bcnt; 37 int cnt[N],C[N]; ll now,ans[N],W[N],V[N]; 38 int pos[N],dfn[N],dep[N],fa[N][D],vis[N],st[N],pre[N]; 39 40 struct Node 41 { 42 int id,u,v,t; 43 bool operator < (const Node& rhs) const 44 { 45 if(pos[u]==pos[rhs.u]&&pos[v]==pos[rhs.v]) return t<rhs.t; 46 else if(pos[u]==pos[rhs.u]) return pos[v]<pos[rhs.v]; 47 else return pos[u]<pos[rhs.u]; 48 } 49 } q[N]; 50 struct opNode { int u,v,pre; 51 } que[N]; 52 53 int qs,cs; 54 55 int dfs(int u) 56 { 57 FOR(i,1,D-1) 58 fa[u][i]=fa[fa[u][i-1]][i-1]; 59 dfn[u]=++dfsc; 60 int siz=0; 61 trav(u,i) { 62 int v=e[i].v; 63 if(v!=fa[u][0]) { 64 fa[v][0]=u; 65 dep[v]=dep[u]+1; 66 siz+=dfs(v); 67 if(siz>=B) { 68 Bcnt++; 69 while(siz--) 70 pos[st[top--]]=Bcnt; 71 } 72 } 73 } 74 st[++top]=u; 75 return siz+1; 76 } 77 int lca(int u,int v) 78 { 79 if(dep[u]<dep[v]) swap(u,v); 80 int t=dep[u]-dep[v]; 81 FOR(i,0,D-1) 82 if(t&(1<<i)) u=fa[u][i]; 83 if(u==v) return u; 84 for(int i=D-1;i>=0;i--) 85 if(fa[u][i]!=fa[v][i]) 86 u=fa[u][i],v=fa[v][i]; 87 return fa[u][0]; 88 } 89 void Xor(int u) 90 { 91 if(vis[u]) 92 vis[u]=0,now-=V[C[u]]*W[cnt[C[u]]--]; 93 else 94 vis[u]=1,now+=V[C[u]]*W[++cnt[C[u]]]; 95 } 96 void upd(int u,int v) 97 { 98 if(vis[u]) { 99 Xor(u); C[u]=v; Xor(u); 100 } 101 else 102 C[u]=v; 103 } 104 void work(int u,int v) 105 { 106 while(u!=v) { 107 if(dep[u]<dep[v]) swap(u,v); 108 Xor(u); u=fa[u][0]; 109 } 110 } 111 112 int main() 113 { 114 // freopen("in.in","r",stdin); 115 // freopen("out.out","w",stdout); 116 n=read(),m=read(),Q=read(); 117 B=pow(n,2.0/3)*0.5; 118 FOR(i,1,m) V[i]=read(); 119 FOR(i,1,n) W[i]=read(); 120 int op,u,v,w; 121 FOR(i,1,n-1) { 122 u=read(),v=read(); 123 adde(u,v),adde(v,u); 124 } 125 FOR(i,1,n) 126 pre[i]=C[i]=read(); 127 128 dfs(1); 129 ++Bcnt; 130 while(top) pos[st[top--]]=Bcnt; 131 FOR(i,1,Q) 132 { 133 op=read(),u=read(),v=read(); 134 if(op==0) { 135 ++cs; 136 que[cs].u=u,que[cs].v=v; 137 que[cs].pre=pre[u]; pre[u]=v; 138 } else { 139 ++qs; 140 if(dfn[u]>dfn[v]) swap(u,v); 141 q[qs].u=u,q[qs].v=v; 142 q[qs].id=qs; q[qs].t=cs; 143 } 144 } 145 sort(q+1,q+qs+1); 146 FOR(i,1,q[1].t) upd(que[i].u,que[i].v); 147 work(q[1].u,q[1].v); 148 int lc=lca(q[1].u,q[1].v); 149 Xor(lc); 150 ans[q[1].id]=now; 151 Xor(lc); 152 FOR(i,2,qs) 153 { 154 for(int j=q[i-1].t+1;j<=q[i].t;j++) upd(que[j].u,que[j].v); 155 for(int j=q[i-1].t;j>q[i].t;j--) upd(que[j].u,que[j].pre); 156 work(q[i-1].u,q[i].u); 157 work(q[i-1].v,q[i].v); 158 int lc=lca(q[i].u,q[i].v); 159 Xor(lc); 160 ans[q[i].id]=now; 161 Xor(lc); 162 } 163 FOR(i,1,qs) printf("%lld\n",ans[i]); 164 return 0; 165 }
P.S.辣鸡错误毁我青春(摔
说到底还是自己太辣鸡了QAQ
posted on 2016-04-02 11:15 hahalidaxin 阅读(318) 评论(0) 编辑 收藏 举报