【WC2013】糖果公园 [树上莫队]
题意:
一棵树,修改一个点的颜色,询问两点路径上每种颜色的权值$val[c]$*出现次数的权值$cou[w[c]]$的和
树上莫队
按照王室联邦的方法分块,块的大小直径个数有保证,并不需要连通
和带修改莫队一样按照$(pos[u],pos[v],tim)$排序
维护$u,v,cur$三个点,以及每个节点的访问状态$vis[]$,每种颜色出现次数$cou[]$,当前答案$now$
如何移动?
时间移动和序列上一样
$u,v$移动到$u,v'$
$Path(u,v)=Path(u,root) \oplus Path(v,root) \oplus lca(u,v)$
先不管$lca$,令$T(u,v)=Path(u,root) \oplus Path(v,root)$
$T(u,v')=Path(u,root) \oplus Path(v',root)$
经计算$T(u,v')=T(u,v) \oplus T(v,v')$
画一下图很好理解
所以移动的时候我们只要更新$v$到$v'$路径上除去$lca$的所有点就可以了,最后对于每个询问额外把$lca(u,v)$加上
分块大小貌似稍小一点比较好
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> using namespace std; typedef long long ll; const int N=1e5+5; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int n,k,Q,a[N],t[N],op,x,y, val[N]; ll w[N]; struct edge{int v,ne;} e[N<<1]; int cnt,h[N]; inline void ins(int u,int v){ e[++cnt]=(edge){v,h[u]}; h[u]=cnt; e[++cnt]=(edge){u,h[v]}; h[v]=cnt; } int block,m,pos[N]; int st[N],top; void dfs(int u,int fa){ int bot=top; for(int i=h[u];i;i=e[i].ne) if(e[i].v!=fa){ dfs(e[i].v, u); if(top-bot>=block){ m++; while(top!=bot) pos[st[top--]]=m; } } st[++top]=u; } int fa[N][20], deep[N]; void dfs(int u){ for(int i=1; (1<<i)<=deep[u]; i++) fa[u][i]=fa[ fa[u][i-1] ][i-1]; for(int i=h[u];i;i=e[i].ne) if(e[i].v!=fa[u][0]){ deep[ e[i].v ]=deep[u]+1; fa[ e[i].v ][0]=u; dfs(e[i].v); } } inline int lca(int x,int y){ if(deep[x]<deep[y]) swap(x, y); int bin=deep[x]-deep[y]; for(int i=0;i<17;i++) if((1<<i)&bin) x=fa[x][i]; for(int i=17;i>=0;i--) if(fa[x][i]!=fa[y][i]) x=fa[x][i], y=fa[y][i]; return x==y ? x : fa[x][0]; } struct cmeow{int u,next,last;} cq[N]; struct meow{ int u,v,tim,id; bool operator <(const meow &a) const { return pos[u]==pos[a.u] ? (pos[v]==pos[a.v] ? tim<a.tim : pos[v]<pos[a.v]) : pos[u]<pos[a.u]; } }q[N]; int p,tim,u,v,cur; ll now,ans[N]; int vis[N], cou[N]; inline void cha(int u,int d){ int &c=a[u]; if(vis[u]){ now-= w[cou[c]] * val[c]; now-= w[cou[d]] * val[d]; cou[c]--; cou[d]++; now+= w[cou[c]] * val[c]; now+= w[cou[d]] * val[d]; } c=d; } inline void Xor(int u){ int c=a[u]; now-= w[cou[c]] * val[c]; vis[u] ? cou[c]-- : cou[c]++; vis[u]^=1; now+= w[cou[c]] * val[c]; } void move(int x,int y){ if(deep[x]<deep[y]) swap(x, y); while(deep[x]>deep[y]) Xor(x), x=fa[x][0];// printf("%d %lld\n",x,now); while(x!=y) Xor(x), Xor(y), x=fa[x][0], y=fa[y][0]; } void modui(){ u=1; v=1; for(int i=1;i<=p;i++){ while(cur<q[i].tim) cur++, cha(cq[cur].u, cq[cur].next); while(cur>q[i].tim) cha(cq[cur].u, cq[cur].last), cur--; if(u!=q[i].u) move(u, q[i].u), u=q[i].u; if(v!=q[i].v) move(v, q[i].v), v=q[i].v; int anc=lca(u, v); Xor(anc); ans[q[i].id]= now; Xor(anc); } } int main(){ freopen("in","r",stdin); n=read(); k=read(); Q=read(); for(int i=1;i<=k;i++) val[i]=read(); for(int i=1;i<=n;i++) w[i]=read()+w[i-1]; for(int i=1;i<n ;i++) ins(read(), read() ); for(int i=1;i<=n;i++) a[i]=t[i]=read(); block=pow(n,(double)1.9/3); dfs(1, 0); while(top) pos[st[top--]]=m; dfs(1); for(int i=1;i<=Q;i++){ op=read(); x=read(); y=read(); if(op) p++,q[p]=(meow){x,y,tim,p}; else tim++,cq[tim]=(cmeow){x,y,t[x]}, t[x]=y; } sort(q+1, q+1+p); modui(); for(int i=1;i<=p;i++) printf("%lld\n", ans[i]); }
Copyright:http://www.cnblogs.com/candy99/