uoj #58. 【WC2013】糖果公园(树上莫队算法+修改操作)
2016-04-02 11:15
483 查看
【题目链接】
http://uoj.ac/problem/58
【题意】
有一棵树,结点有自己的颜色,若干询问:u,v路径上的获益,并提供修改颜色的操作。
其中获益定义为Vc*W1+Vc*W2+…+Vc*Wcnt,cnt为经过颜色c的次数。
【思路】
如果没有修改操作就和 苹果树 这道题一样了。
加上修改操作,我们可以对每一个修改操作打上一个时间戳,并记录每一个查询最后修改的时间戳。这样在莫队“区间移动”的时候,只需要根据时间戳进行时光逆流或顺流,即加上现在时间内前一个时间没有的修改或消除现在时间内没有前一个时间存在的修改。
对于一个修改,如果已经打上标记即这时候计入了now,我们应该先把它在路径上取反存在性,修改后再取反一下就又以新的权值回到了路上,就是重新计算一下贡献。
【代码】
P.S.辣鸡错误毁我青春(摔
说到底还是自己太辣鸡了QAQ
http://uoj.ac/problem/58
【题意】
有一棵树,结点有自己的颜色,若干询问:u,v路径上的获益,并提供修改颜色的操作。
其中获益定义为Vc*W1+Vc*W2+…+Vc*Wcnt,cnt为经过颜色c的次数。
【思路】
如果没有修改操作就和 苹果树 这道题一样了。
加上修改操作,我们可以对每一个修改操作打上一个时间戳,并记录每一个查询最后修改的时间戳。这样在莫队“区间移动”的时候,只需要根据时间戳进行时光逆流或顺流,即加上现在时间内前一个时间没有的修改或消除现在时间内没有前一个时间存在的修改。
对于一个修改,如果已经打上标记即这时候计入了now,我们应该先把它在路径上取反存在性,修改后再取反一下就又以新的权值回到了路上,就是重新计算一下贡献。
【代码】
#include<set> #include<cmath> #include<queue> #include<vector> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define trav(u,i) for(int i=front[u];i;i=e[i].nxt) #define FOR(a,b,c) for(int a=(b);a<=(c);a++) using namespace std; typedef long long ll; const int N = 3e5+10; const int D = 21; ll read() { char c=getchar(); ll f=1,x=0; while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); } while(isdigit(c)) x=x*10+c-'0',c=getchar(); return x*f; } struct Edge { int v,nxt; }e[N<<2]; int en=1,front ; void adde(int u,int v) { e[++en]=(Edge){v,front[u]}; front[u]=en; } int n,m,B,Q,dfsc,top,Bcnt; int cnt ,C ; ll now,ans ,W ,V ; int pos ,dfn ,dep ,fa [D],vis ,st ,pre ; struct Node { int id,u,v,t; bool operator < (const Node& rhs) const { if(pos[u]==pos[rhs.u]&&pos[v]==pos[rhs.v]) return t<rhs.t; else if(pos[u]==pos[rhs.u]) return pos[v]<pos[rhs.v]; else return pos[u]<pos[rhs.u]; } } q ; struct opNode { int u,v,pre; } que ; int qs,cs; int dfs(int u) { FOR(i,1,D-1) fa[u][i]=fa[fa[u][i-1]][i-1]; dfn[u]=++dfsc; int siz=0; trav(u,i) { int v=e[i].v; if(v!=fa[u][0]) { fa[v][0]=u; dep[v]=dep[u]+1; siz+=dfs(v); if(siz>=B) { Bcnt++; while(siz--) pos[st[top--]]=Bcnt; } } } st[++top]=u; return siz+1; } int lca(int u,int v) { if(dep[u]<dep[v]) swap(u,v); int t=dep[u]-dep[v]; FOR(i,0,D-1) if(t&(1<<i)) u=fa[u][i]; if(u==v) return u; for(int i=D-1;i>=0;i--) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i]; return fa[u][0]; } void Xor(int u) { if(vis[u]) vis[u]=0,now-=V[C[u]]*W[cnt[C[u]]--]; else vis[u]=1,now+=V[C[u]]*W[++cnt[C[u]]]; } void upd(int u,int v) { if(vis[u]) { Xor(u); C[u]=v; Xor(u); } else C[u]=v; } void work(int u,int v) { while(u!=v) { if(dep[u]<dep[v]) swap(u,v); Xor(u); u=fa[u][0]; } } int main() { // freopen("in.in","r",stdin); // freopen("out.out","w",stdout); n=read(),m=read(),Q=read(); B=pow(n,2.0/3)*0.5; FOR(i,1,m) V[i]=read(); FOR(i,1,n) W[i]=read(); int op,u,v,w; FOR(i,1,n-1) { u=read(),v=read(); adde(u,v),adde(v,u); } FOR(i,1,n) pre[i]=C[i]=read(); dfs(1); ++Bcnt; while(top) pos[st[top--]]=Bcnt; FOR(i,1,Q) { op=read(),u=read(),v=read(); if(op==0) { ++cs; que[cs].u=u,que[cs].v=v; que[cs].pre=pre[u]; pre[u]=v; } else { ++qs; if(dfn[u]>dfn[v]) swap(u,v); q[qs].u=u,q[qs].v=v; q[qs].id=qs; q[qs].t=cs; } } sort(q+1,q+qs+1); FOR(i,1,q[1].t) upd(que[i].u,que[i].v); work(q[1].u,q[1].v); int lc=lca(q[1].u,q[1].v); Xor(lc); ans[q[1].id]=now; Xor(lc); FOR(i,2,qs) { for(int j=q[i-1].t+1;j<=q[i].t;j++) upd(que[j].u,que[j].v); for(int j=q[i-1].t;j>q[i].t;j--) upd(que[j].u,que[j].pre); work(q[i-1].u,q[i].u); work(q[i-1].v,q[i].v); int lc=lca(q[i].u,q[i].v); Xor(lc); ans[q[i].id]=now; Xor(lc); } FOR(i,1,qs) printf("%lld\n",ans[i]); return 0; }
P.S.辣鸡错误毁我青春(摔
说到底还是自己太辣鸡了QAQ
相关文章推荐
- NuGet packages引用包多版本存档清理
- java基础语法注意点归纳总结
- frameSet控制页面布局
- 5-15 计算圆周率 (15分)
- 二叉树和二叉查找树
- 遗传算法入门(连载之三)
- 让eclipse代码编辑器换下皮肤
- 数据库操作
- 这十二行代码是如何让浏览器爆炸的? -DoS攻击分析及防御
- Java内存区域分析
- shell脚本实现检測回文字符串
- 2016年 最火的 15 款 HTML5 游戏引擎
- 【Unity】3.2 利用预设(Prefab)制作可复用的组件
- ImageLoader实现图片异步加载
- C语言函数和汇编函数相互调用
- 【JQuery】使用remove()和empty()方法删除元素
- python实现K近邻
- Android-Fragment和Activity的传值通信
- 树的非递归遍历
- 蓝鲸python第二题个人理解版