博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【BZOJ4999】This Problem Is Too Simple! 离线+树状数组+LCA
阅读量:5218 次
发布时间:2019-06-14

本文共 2672 字,大约阅读时间需要 8 分钟。

【BZOJ4999】This Problem Is Too Simple!

Description

给您一颗树,每个节点有个初始值。
现在支持以下两种操作:
1. C i x(0<=x<2^31) 表示将i节点的值改为x。
2. Q i j x(0<=x<2^31) 表示询问i节点到j节点的路径上有多少个值为x的节点。

Input

第一行有两个整数N,Q(1 ≤N≤ 100,000;1 ≤Q≤ 200,000),分别表示节点个数和操作个数。
下面一行N个整数,表示初始时每个节点的初始值。
接下来N-1行,每行两个整数x,y,表示x节点与y节点之间有边直接相连(描述一颗树)。
接下来Q行,每行表示一个操作,操作的描述已经在题目描述中给出。

Output

对于每个Q输出单独一行表示所求的答案。

Sample Input

5 6
10 20 30 40 50
1 2
1 3
3 4
3 5
Q 2 3 40
C 1 40
Q 2 3 40
Q 4 5 30
C 3 10
Q 4 5 30

Sample Output

0
1
1
0

题解:由于每种颜色相互独立,可以考虑离线。将修改操作变成一个颜色的删除操作和另一个颜色的加入操作,然后将所有操作和询问都按颜色和时间排序,分别处理每一个颜色。然后我们只需要倍增LCA+动态维护所有点到根路径上的权值即可。单点权值+a等于它子树中所有点到根路径上的权值都+a,所以用树状数组维护DFS序即可。

竟然因为数组开小而WA了一天~

 

#include 
#include
#include
#include
using namespace std;const int maxn=200010;int n,m,Q,cnt,now,tot;struct node{ int col,x,val,tim;}p[maxn*5];struct QUERY{ int col,a,b,tim,org;}q[maxn];char str[10];int to[maxn<<1],next[maxn<<1],head[maxn],p1[maxn],p2[maxn],dep[maxn],fa[19][maxn],v[maxn];int Log[maxn],s[maxn],vis[maxn],ans[maxn];void add(int a,int b){ to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;}void dfs(int x){ p1[x]=++p2[0]; for(int i=head[x];i!=-1;i=next[i]) if(to[i]!=fa[0][x]) fa[0][to[i]]=x,dep[to[i]]=dep[x]+1,dfs(to[i]); p2[x]=p2[0];}bool cmpp(node a,node b){ return (a.col==b.col)?(a.tim
=0;i--) if(dep[fa[i][a]]>=dep[b]) a=fa[i][a]; if(a==b) return a; for(int i=Log[dep[a]];i>=0;i--) if(fa[i][a]!=fa[i][b]) a=fa[i][a],b=fa[i][b]; return fa[0][a];}inline int rd(){ int ret=0,f=1; char gc=getchar(); while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();} while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar(); return ret*f;}int main(){ n=rd(),m=rd(); int i,j,a,b,c; memset(head,-1,sizeof(head)); for(i=1;i<=n;i++) v[i]=p[++tot].col=rd(),p[tot].x=i,p[tot].tim=0,p[tot].val=1; for(i=2;i<=n;i++) a=rd(),b=rd(),add(a,b),add(b,a); dep[1]=1,dfs(1); for(i=2;i<=n;i++) Log[i]=Log[i>>1]+1; for(j=1;(1<
<=n;j++) for(i=1;i<=n;i++) fa[j][i]=fa[j-1][fa[j-1][i]]; for(i=1;i<=m;i++) { scanf("%s",str),a=rd(),b=rd(); if(str[0]=='C') { tot+=2,p[tot-1].x=p[tot].x=a,p[tot-1].col=v[a],v[a]=p[tot].col=b; p[tot-1].tim=p[tot].tim=i,p[tot-1].val=-1,p[tot].val=1; } else q[++Q].a=a,q[Q].b=b,q[Q].col=rd(),q[Q].org=Q,q[Q].tim=i; } sort(p+1,p+tot+1,cmpp); sort(q+1,q+Q+1,cmpq); for(i=j=1;i<=Q;i++) { for(;(p[j].col
<=tot;j++) { now=p[j].col; updata(p1[p[j].x],p[j].val),updata(p2[p[j].x]+1,-p[j].val); } if(now==q[i].col) { a=q[i].a,b=q[i].b,c=lca(a,b); ans[q[i].org]=query(p1[a])+query(p1[b])-query(p1[c])-query(p1[fa[0][c]]); } } for(i=1;i<=Q;i++) printf("%d\n",ans[i]); return 0;}

 

转载于:https://www.cnblogs.com/CQzhangyu/p/7468744.html

你可能感兴趣的文章
Count Numbers
查看>>
编写高质量代码改善C#程序的157个建议——建议110:用类来代替enum
查看>>
网卡bond技术
查看>>
UITabbarController的UITabbarItem(例:"我的")点击时,判断是否登录
查看>>
UNIX基础知识之输入和输出
查看>>
【洛谷 P1666】 前缀单词 (Trie)
查看>>
对称加密和非对称加密
查看>>
数据库锁机制及乐观锁,悲观锁的并发控制
查看>>
图像处理中双线性插值
查看>>
RobHess的SIFT代码解析之RANSAC
查看>>
03 线程池
查看>>
201771010125王瑜《面向对象程序设计(Java)》第十三周学习总结
查看>>
java中内部类的讲解
查看>>
手机验证码执行流程
查看>>
python 基础 ----- 变量
查看>>
设计模式课程 设计模式精讲 2-2 UML类图讲解
查看>>
Silverlight 的菜单控件。(不是 Toolkit的)
查看>>
:hover 鼠标同时触发两个元素变化
查看>>
go语言学习十三 - 相等性
查看>>
Idea 提交代码到码云(提交到github也大同小异)
查看>>