[bzoj3052][WC2013]糖果公园
2016-05-09 20:08
302 查看
题目大意
给定一颗n个结点的树。每个结点有一种颜色。颜色种类为m。一条路径的价值定义为
∑i=1mw[cnt[i]]∗v[i]
其中cnt[i]表示这条路径上颜色i出现的次数。
现有q个操作,每个操作要么是询问一条路径的价值,要么是将一个结点的颜色种类修改。
带修改莫队
这是树上莫队,我们接下来只讨论序列莫队,树上莫队可以转化为序列莫队。带修改莫队怎么做呀?
分块大小设为n23
对于每个询问,用三元组表示(l,r,x)表示询问区间为[l,r]然后是在第x次修改操作后。
以左端点所在块为第一关键字,右端点所在块为第二关键字,已经经过的修改次数为第三关键字排序。
那么就和二维的莫队差不多,你只是需要额外兹瓷修改操作与撤销修改操作(其实都是修改操作)
可以证明总共的复杂度是o(n53)
本题我的分块大小是取了1750。
#include<cstdio> #include<algorithm> #include<cmath> #define fo(i,a,b) for(i=a;i<=b;i++) #define fd(i,a,b) for(i=a;i>=b;i--) using namespace std; typedef long long ll; const int maxn=100000+10; struct dong{ int l,r,x,id,w; bool p; }; int belong[maxn*2]; bool operator <(dong a,dong b){ if (belong[a.l]<belong[b.l]) return 1; else if (belong[a.l]==belong[b.l]&&belong[a.r]<belong[b.r]) return 1; else if (belong[a.l]==belong[b.l]&&belong[a.r]==belong[b.r]&&a.x<b.x) return 1; else return 0; } dong ask[maxn]; int v[maxn],w[maxn],cnt[maxn],fi[maxn],la[maxn],a[maxn*2],c[maxn]; int h[maxn],go[maxn*2],next[maxn*2],b[maxn][3]; int f[maxn][25],d[maxn]; ll ans[maxn]; bool bz[maxn]; int i,j,k,l,r,x,t,n,m,q,block,tot,top,num,sum; ll now; void add(int x,int y){ go[++tot]=y; next[tot]=h[x]; h[x]=tot; } void dfs(int x,int y){ fi[x]=++top; a[top]=x; d[x]=d[y]+1; f[x][0]=y; int t=h[x]; while (t){ if (go[t]!=y) dfs(go[t],x); t=next[t]; } la[x]=++top; a[top]=x; } int lca(int x,int y){ int j; if (d[x]<d[y]) swap(x,y); if (d[x]!=d[y]){ j=floor(log(d[x]-d[y])/log(2)); while (j>=0){ if (d[f[x][j]]>d[y]) x=f[x][j]; j--; } x=f[x][0]; } if (x==y) return x; j=floor(log(d[x])/log(2)); while (j>=0){ if (f[x][j]!=f[y][j]){ x=f[x][j]; y=f[y][j]; } j--; } return f[x][0]; } void change(int x){ bz[x]^=1; if (bz[x]){ cnt[c[x]]++; now+=(ll)w[cnt[c[x]]]*v[c[x]]; } else{ now-=(ll)w[cnt[c[x]]]*v[c[x]]; cnt[c[x]]--; } } void in(int x){ if (bz[b[x][2]]){ now-=(ll)w[cnt[b[x][0]]]*v[b[x][0]]; cnt[b[x][0]]--; cnt[b[x][1]]++; now+=(ll)w[cnt[b[x][1]]]*v[b[x][1]]; } c[b[x][2]]=b[x][1]; } void out(int x){ if (bz[b[x][2]]){ now-=(ll)w[cnt[b[x][1]]]*v[b[x][1]]; cnt[b[x][1]]--; cnt[b[x][0]]++; now+=(ll)w[cnt[b[x][0]]]*v[b[x][0]]; } c[b[x][2]]=b[x][0]; } int main(){ scanf("%d%d%d",&n,&m,&q); fo(i,1,m) scanf("%d",&v[i]); fo(i,1,n) scanf("%d",&w[i]); fo(i,1,n-1){ scanf("%d%d",&j,&k); add(j,k);add(k,j); } dfs(1,0); fo(j,1,floor(log(n)/log(2))) fo(i,1,n) f[i][j]=f[f[i][j-1]][j-1]; fo(i,1,n) scanf("%d",&c[i]); fo(i,1,q){ scanf("%d",&t); if (!t){ scanf("%d%d",&j,&k); b[++num][0]=c[j]; b[num][1]=c[j]=k; b[num][2]=j; } else{ scanf("%d%d",&j,&k); t=lca(j,k); if (t==j||t==k){ ask[++sum].p=0; l=fi[j];r=fi[k]; if (l>r) swap(l,r); } else{ ask[++sum].p=1; ask[sum].w=t; if (fi[j]>fi[k]) swap(j,k); l=la[j];r=fi[k]; } ask[sum].l=l;ask[sum].r=r; ask[sum].id=sum; ask[sum].x=num; } } fd(i,num,1) c[b[i][2]]=b[i][0]; block=1750; fo(i,1,2*n) belong[i]=(i-1)/block+1; sort(ask+1,ask+sum+1); l=r=1;x=0; change(a[1]); fo(i,1,sum){ while (x>ask[i].x){ out(x); x--; } while (x<ask[i].x){ x++; in(x); } while (l>ask[i].l){ l--; change(a[l]); } while (l<ask[i].l){ change(a[l]); l++; } while (r<ask[i].r){ r++; change(a[r]); } while (r>ask[i].r){ change(a[r]); r--; } if (ask[i].p) change(ask[i].w); ans[ask[i].id]=now; if (ask[i].p) change(ask[i].w); } fo(i,1,sum) printf("%lld\n",ans[i]); }
相关文章推荐
- Spring源码解析—— ClassPathResource类
- 图像处理的仿射变换和透视变换
- Spring源码解析—— ClassPathResource类
- android 编写拦截拦截短信的service
- 自学android, java, html, css, php, mysql, javascript路线
- 冒泡排序的两种写法
- 在Linux防火墙上过滤外来的ICMP timestamp
- 机器学习 : 高斯混合模型及EM算法
- 编程之美之买书
- 垃圾回收之引用计数之循环引用
- 初学Shiro
- MagicalRecord(简化CoreData操作)
- PAT 乙级 1007. 素数对猜想 (20)
- 一个图书售卖网页
- nyoj 123 士兵杀敌(四)
- Codeforces Round #151 (Div. 2) C. Beauty Pageant
- 给VirtualBox上的Ubuntu虚拟机扩展硬盘空间
- 第十一周【项目1 - 点-圆-圆柱类族的设计2】
- HDU 1850-Being a Good Boy in Spring Festival(Nim博弈)
- PHP数据类型转换