GDOI2016模拟8.14数树数
来源:互联网 发布:ip提取器源码 编辑:程序博客网 时间:2024/04/29 16:13
题目
给定一棵N 个节点的树,标号从1~N。每个点有一个权值。要求维护两种操作:
1. C i x(0<=x<2^31) 表示将i 点权值变为x
2. Q i j x(0<=x<2^31) 表示询问i 到j 的路径上有多少个值为x 的节点
比较简单的想法就是按权值建N+Q棵可持久化线段树,第i棵线段树里记录权值为a[i]的节点的区间和,节点要用链剖后的dfs序来做编号,修改时就是将原权值所在线段树中的点删除,在新权值线段树里插入,查询就沿重链往上跳,先跳深度大的,然后在线段树里查询就行了。
时间复杂度:(N+Q)(log(N+Q))^2
空间复杂度:(N+Q)(log(N+Q))
贴代码
#include<iostream>#include<cstdio>#include<algorithm>#define N 300001using namespace std;int n,m,sum,ans;int fa[N],q[N][4],g[N],a[N+N][2],f[N*36][3],bz[N],h[N],v[N],b[N][2],c[N],w[N];void ins(int x,int y){ static int sum=0; a[++sum][0]=y,a[sum][1]=g[x],g[x]=sum;}void init(){ static char x; static int y,z; scanf("%d %d",&n,&m); for (int i=1;i<=n;i++) scanf("%d",&v[i]),c[++c[0]]=v[i]; for (int i=1;i<n;i++) scanf("%d %d",&y,&z),ins(y,z),ins(z,y); for (int i=1;i<=m;i++){ scanf(" %c %d %d",&x,&q[i][1],&q[i][2]); if (x=='Q') scanf("%d",&q[i][3]),q[i][0]=1; else c[++c[0]]=q[i][2]; }}void dfs(int x){ for (int i=g[x];i;i=a[i][1]) if (a[i][0]!=fa[x]){ fa[a[i][0]]=x; dfs(a[i][0]); if (b[x][0]<b[a[i][0]][0]+1) b[x][0]=b[a[i][0]][0]+1,b[x][1]=a[i][0]; }}void dfs1(int x){ static int sum=0; bz[x]=++sum; if (b[x][1]) h[b[x][1]]=h[x],dfs1(b[x][1]); for (int i=g[x];i;i=a[i][1]) if (a[i][0]!=fa[x]&&a[i][0]!=b[x][1]) h[a[i][0]]=a[i][0],dfs1(a[i][0]);}void change(int l,int r,int s,int ll,int z){ f[s][2]+=z; if (l==r)return; static int ss; if ((ss=(l+r)/2)>=ll){ if (!f[s][0])f[s][0]=++sum; change(l,ss,f[s][0],ll,z); }else{ if (!f[s][1])f[s][1]=++sum; change(ss+1,r,f[s][1],ll,z); }}int er(int x){ static int l,r,mid; l=1,r=c[0]; while (l<=r)if (c[mid=(l+r)/2]<x)l=mid+1;else r=mid-1; if (l<1)l=1; if (l>c[0])l=c[0]; while (c[l]<x&&l<c[0])l++; while (c[l]>x&&l>1)l--; return l;}void pre(){ static int x; sort(c+1,c+c[0]+1); x=c[0],c[0]=1; for (int i=2;i<=x;i++) if (c[c[0]]!=c[i])c[++c[0]]=c[i]; dfs(1); h[1]=1; dfs1(1); for (int i=1;i<=c[0];i++) w[i]=++sum; for (int i=1;i<=n;i++) change(1,n,w[er(v[i])],bz[i],1);}void find(int l,int r,int s,int ll,int rr){ if (!f[s][2])return; if (rr<l||r<ll)return; if (ll<=l&&r<=rr){ ans+=f[s][2]; return; } find(l,(l+r)/2,f[s][0],ll,rr),find((l+r)/2+1,r,f[s][1],ll,rr);}void up(int x,int y,int z){ static int ss; ss=z; z=er(z); if (c[z]!=ss)return; while (h[x]!=h[y]){ if (bz[h[x]]<bz[h[y]])swap(x,y); find(1,n,w[z],bz[h[x]],bz[x]); x=fa[h[x]]; } if (bz[x]<bz[y])swap(x,y); find(1,n,w[z],bz[y],bz[x]);}void work(){ for (int i=1;i<=m;i++) if (q[i][0]){ ans=0; up(q[i][1],q[i][2],q[i][3]); printf("%d\n",ans); }else{ change(1,n,w[er(v[q[i][1]])],bz[q[i][1]],-1); v[q[i][1]]=q[i][2]; change(1,n,w[er(q[i][2])],bz[q[i][1]],1); }}int main(){ init(); pre(); work(); return 0;}
0 0
- GDOI2016模拟8.14数树数
- GDOI2016模拟8.14总结
- GDOI2016模拟8.14电话表
- GDOI2016模拟8.14扫雷游戏
- GDOI2016模拟8.10踢足球
- GDOI2016模拟8.8旋转
- GDOI2016模拟8.8处理器
- GDOI2016模拟8.13总结
- GDOI2016模拟8.15总结
- GDOI2016模拟8.15蜘蛛侠
- GDOI2016模拟8.15送票
- GDOI2016模拟8.16总结
- GDOI2016模拟8.16帮派
- GDOI2016模拟8.18总结
- GDOI2016模拟8.18蜡笔
- GDOI2016模拟8.18的士
- GDOI2016模拟8.18解密
- GDOI2016模拟8.19总结
- hdu 1708
- java基础视频需要记忆的部分备忘 - 正则表达式
- poj 1484 Blowing Fuses
- POJ - 1062 昂贵的聘礼(最短路Dijkstra)
- 解决编译opencv3.0时出现的问题undefined reference to `parallel_pthreads_set_threads_num(int)'
- GDOI2016模拟8.14数树数
- hdu1021
- IOS 创建TLV数据流
- Java基础——网络编程(待续)
- **IOS开发之关键字category(类别)详解**
- hud1250
- Java多线程总结笔记(二)—— 线程各状态及转换
- 再谈工厂三姐妹
- hdu 3635 Dragon Balls(带权并查集)