BZOJ 4817: [Sdoi2017]树点涂色(LCT+树剖+线段树)
题目描述
Bob有一棵 nn 个点的有根树,其中1号点是根节点。Bob在每个点上涂了颜色,并且每个点上的颜色不同。
定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。
Bob可能会进行这几种操作:
- 1 x
把点 xx 到根节点的路径上所有的点染上一种没有用过的新颜色。
- 2 x y
求 xx 到 yy 的路径的权值。
- 3 x
在以x为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。
Bob一共会进行 mm 次操作
输入输出格式
输入格式:
第一行两个数 n,mn,m 。
接下来 n-1n−1 行,每行两个数 a,ba,b ,表示 aa 与 bb 之间有一条边。
接下来 mm 行,表示操作,格式见题目描述
输出格式:
每当出现2,3操作,输出一行。
如果是2操作,输出一个数表示路径的权值
如果是3操作,输出一个数表示权值的最大值
输入输出样例
5 6 1 2 2 3 3 4 3 5 2 4 5 3 3 1 4 2 4 5 1 5 2 4 5
3 4 2 2
说明
共10个测试点
测试点1, 1\leq n,m\leq10001≤n,m≤1000
测试点2、3,没有2操作
测试点4、5,没有3操作
测试点6,树的生成方式是,对于 i(2\leq i \leq n)i(2≤i≤n) ,在1到 i-1i−1 中随机选一个点作为i的父节点。
测试点7, 1\leq n,m\leq 500001≤n,m≤50000
测试点8, 1\leq n \leq 500001≤n≤50000
测试点9,10,无特殊限制
对所有数据, 1\leq n \leq 10^51≤n≤105 , 1\leq m \leq 10^51≤m≤105
时间限制:1s
空间限制:128MB
题解
照例先膜一发大佬
说真的是道好题,LCT,树剖,dfs序,线段树都得用上
然后抄题解抄得不亦乐乎悲催的没有发现一个地方我和大佬思路是完全不一样的……
后来因为这个地方调了整整一个小时……我少了一个小时的睡觉时间!!!
先讲个思路……
操作一
因为颜色都不一样,也没有必要维护颜色了
然后我们能发现,任何时候同一个颜色必定是一条链,而且深度严格递增
很显然,因为每一次颜色修改只会在到根的路径上进行
所以每一个颜色都可以用LCT中的splay来维护了
并且我们发现,操作一不就是LCT中的access么?
操作二
每一个颜色都在一个splay中
所以一条路径上的颜色数量就是跨过了几个splay,也就是经过了几条虚边
于是split就好了显然是行不通的,因为因为乱搞会破坏掉关系
然后可以考虑用树上差分
$f[x]+f[y]-2*f[lca(x,y)]+1$就是这条路径上的颜色数量了(lca被减了两次要加回来)(f表示到根节点的虚边数量)
然后考虑怎么维护$f$
刚开始时是节点的深度
然后显然access的时候会对$f$有影响,一条边变虚,一条边变实
所以只要把原来的虚边指向的子树答案全部+1,实边指向的子树答案全部-1
这就是一个子树操作啦
用线段树+dfs序,可以很轻松的完成子树操作
操作三
查询其实和修改差不多
直接线段树查询即可
ps:写的树剖求LCA,结果因为原树和splay都要维护father,看了看大佬的板子只用了一个数组,结果莫名其妙T到死……算了滚去睡觉了(¦3[▓▓]实在太困了……
1 //minamoto 2 #include<iostream> 3 #include<cstdio> 4 using std::swap; 5 using std::max; 6 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 7 char buf[1<<21],*p1=buf,*p2=buf; 8 inline int read(){ 9 #define num ch-'0' 10 char ch;bool flag=0;int res; 11 while(!isdigit(ch=getc())) 12 (ch=='-')&&(flag=true); 13 for(res=num;isdigit(ch=getc());res=res*10+num); 14 (flag)&&(res=-res); 15 #undef num 16 return res; 17 } 18 char obuf[1<<24],*o=obuf; 19 inline void print(int x){ 20 if(x>9) print(x/10); 21 *o++=x%10+48; 22 } 23 const int N=100005,M=N*20; 24 int fa[N],f[N],ch[N][2],sz[N],son[N],dfn[N],rk[N]; 25 int dep[N],top[N],L[M],R[M],mx[M],lz[M],rs[N],mid[M]; 26 int head[N],Next[N<<1],ver[N<<1]; 27 int n,m,cnt,num,tot; 28 inline void add(int u,int v){ 29 ver[++tot]=v,Next[tot]=head[u],head[u]=tot; 30 ver[++tot]=u,Next[tot]=head[v],head[v]=tot; 31 } 32 void dfs1(int u){ 33 sz[u]=1,dep[u]=dep[f[u]]+1; 34 dfn[u]=++num,rk[num]=u; 35 for(int i=head[u];i;i=Next[i]){ 36 int v=ver[i]; 37 if(v==f[u]) continue; 38 fa[v]=f[v]=u; 39 dfs1(v); 40 sz[u]+=sz[v]; 41 if(!son[u]||sz[v]>sz[son[u]]) son[u]=v; 42 } 43 rs[u]=num; 44 } 45 void dfs2(int u){ 46 if(!top[u]) top[u]=u; 47 if(!son[u]) return; 48 top[son[u]]=top[u],dfs2(son[u]); 49 for(int i=head[u];i;i=Next[i]){ 50 int v=ver[i]; 51 if(v!=f[u]&&v!=son[u]) dfs2(v); 52 } 53 } 54 inline int LCA(int u,int v){ 55 while(top[u]!=top[v]) 56 dep[top[u]]>dep[top[v]]?u=f[top[u]]:v=f[top[v]]; 57 return dep[u]<dep[v]?u:v; 58 } 59 inline void build(int p,int l,int r){ 60 L[p]=l,R[p]=r,mid[p]=(l+r)>>1; 61 if(l==r)return (void)(mx[p]=dep[rk[l]]); 62 build(p<<1,l,mid[p]),build(p<<1|1,mid[p]+1,r); 63 mx[p]=max(mx[p<<1],mx[p<<1|1]); 64 } 65 #define pushdown if(lz[p]) update(p<<1,L[p],mid[p],lz[p]),update(p<<1|1,mid[p]+1,R[p],lz[p]),lz[p]=0 66 void update(int p,int l,int r,int v){ 67 if(L[p]==l&&R[p]==r){mx[p]+=v,lz[p]+=v;return;} 68 pushdown; 69 if(r<=mid[p]) update(p<<1,l,r,v); 70 else if(l>mid[p]) update(p<<1|1,l,r,v); 71 else update(p<<1,l,mid[p],v),update(p<<1|1,mid[p]+1,r,v); 72 mx[p]=max(mx[p<<1],mx[p<<1|1]); 73 } 74 int get(int v){ 75 int p=1; 76 while(L[p]!=R[p]){ 77 pushdown;p=(p<<1)+(v>mid[p]); 78 /*pushdown后面逗号竟然死循环了……*/ 79 } 80 return mx[p]; 81 } 82 int ask(int p,int l,int r){ 83 if(L[p]==l&&R[p]==r) return mx[p]; 84 pushdown; 85 if(r<=mid[p]) return ask(p<<1,l,r); 86 if(l>mid[p]) return ask(p<<1|1,l,r); 87 return max(ask(p<<1,l,mid[p]),ask(p<<1|1,mid[p]+1,r)); 88 } 89 #undef pushdown 90 bool isroot(int x){ 91 return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x; 92 } 93 void rotate(int x){ 94 int y=fa[x],z=fa[y],d=ch[y][1]==x; 95 if(!isroot(y)) ch[z][ch[z][1]==y]=x; 96 fa[x]=z,fa[y]=x,fa[ch[x][d^1]]=y,ch[y][d]=ch[x][d^1],ch[x][d^1]=y; 97 } 98 void splay(int x){ 99 for(int y=fa[x];!isroot(x);y=fa[x]){ 100 if(!isroot(y)) 101 rotate(x); 102 rotate(x); 103 } 104 } 105 int findroot(int x){ 106 while(ch[x][0]) x=ch[x][0]; 107 return x; 108 } 109 void access(int x){ 110 for(int w,y=0;x;x=fa[y=x]){ 111 splay(x); 112 if(ch[x][1]) w=findroot(ch[x][1]),update(1,dfn[w],rs[w],1); 113 if((ch[x][1]=y)) w=findroot(y),update(1,dfn[w],rs[w],-1); 114 /*把原来的子树变为虚的,整个子树的答案+1 115 然后新的子树答案-1*/ 116 } 117 } 118 int main(){ 119 //freopen("testdata.in","r",stdin); 120 int n=read(),m=read(); 121 for(int i=1;i<n;++i){ 122 int u=read(),v=read(); 123 add(u,v); 124 } 125 dfs1(1),dfs2(1),build(1,1,n); 126 while(m--){ 127 int opt=read(),x=read(); 128 switch(opt){ 129 case 1:{ 130 access(x); 131 break; 132 } 133 case 2:{ 134 int y=read(); 135 print(get(dfn[x])+get(dfn[y])-get(dfn[LCA(x,y)])*2+1),*o++='\n'; 136 break; 137 } 138 case 3:{ 139 print(ask(1,dfn[x],rs[x])),*o++='\n'; 140 break; 141 } 142 } 143 } 144 fwrite(obuf,o-obuf,1,stdout); 145 return 0; 146 }
转载于:https://www.cnblogs.com/bztMinamoto/p/9420600.html
BZOJ 4817: [Sdoi2017]树点涂色(LCT+树剖+线段树)相关推荐
- 【BZOJ4817】【SDOI2017】树点涂色 [LCT][线段树]
树点涂色 Time Limit: 10 Sec Memory Limit: 128 MB [Submit][Status][Discuss] Description Bob有一棵n个点的有根树,其中 ...
- BZOJ 4817: [Sdoi2017]树点涂色
4817: [Sdoi2017]树点涂色 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 273 Solved: 164 [Submit][Stat ...
- [Bzoj4817] [Sdoi2017]树点涂色 (LCT神题)
4817: [Sdoi2017]树点涂色 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 629 Solved: 371 [Submit][Stat ...
- 【线段树】【LCT】【LCA】树点涂色(luogu 3703)
树点涂色 luogu 3703 题目大意 给出一棵树,每个节点的初始颜色不同,做若干操作: 1.在一个点到根节点路径上染上一种新的颜色 2.查询一条路径上有多少种不同的颜色 3.查询一个点x,使该点到 ...
- [BZOJ3779]重组病毒(LCT+DFS序线段树)
同[BZOJ4817]树点涂色,只是多了换根操作,分类讨论下即可. 1 #include<cstdio> 2 #include<algorithm> 3 #define lc ...
- BZOJ3531-[Sdoi2014]旅行(树剖+线段树动态开点)
传送门 完了今天才知道原来线段树的动态开点和主席树是不一样的啊 我们先考虑没有宗教信仰的限制,那么就是一个很明显的树剖+线段树,路径查询最大值以及路径和 然后有了宗教信仰的限制该怎么做呢? 先考虑暴力 ...
- c语言线段树建树程序,c语言数据结构之线段树详解;例题:校门外的树(poj2808或者vijos1448)...
线段树:它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个结点. 也就是说线段树的每一个结点对应一个区间,其中根节点对应区间[1,n] 对于线段树中的每一个非叶子节点[a,b],它的左儿子 ...
- Bzoj4817:[SDOI2017]树点涂色
题面 Bzoj Sol 做个转化 最开始都是虚边 操作\(1\)就是\(LCT\)里的\(Access\)操作 求的就是路径上虚边的个数+1 然后就好办了 用树链剖分+线段树来维护每个点到根虚边的个数 ...
- bzoj4817: [Sdoi2017]树点涂色
震惊!LCT还能这么用! 这个颜色修改的特点是点到根 搜刮一下性质,颜色从根到某个点是分层次单调增的,而且同一个点的两个不同儿子不会有相同颜色,也就是相同颜色的点是树上自上往下的一条链 前面这些都是次 ...
最新文章
- python输入函数格式_python如何提取.c文件中的指定函数的输入参数
- 两台linux之间实现共享文件夹挂载实例,linux之间实现共享文件夹挂载实力
- 手把手教你如何用Python制作一个电子相册?末附python教程
- NJUST1712(形成三角形面积为整数的个数)
- 宝塔需在php设置中安装redis扩展,wordpress开启Redis扩展教程
- AT2645 [ARC076D] Exhausted?(Hall定理推论/线段树+扫描线)
- stripe pay_J2Pay –实施网关
- 十九、MySQL常用命令总结
- Linux的Vi命令详解
- AAA和radius协议学习
- u盘容量足够,但是提示目标文件过大无法复制的解决办法
- 2020年你还不会做绿幕特效?这4步基础技巧要点了解一下!
- Arcgis使用教程(九)ARCGIS空间数据符号化
- 小程序中getUserProfile使用async和await时fail,提示:can only be invoked by user TAP gesture
- Gtalent如何帮助HR招到薪酬专员,5条建议4点做法
- 导航条动态模糊效果实现原理实战
- 介绍python库的书籍_【介】 介怎么读|组词|读音|拼音|多音字|意思 - 辞海之家
- 国际期刊预警名单网址
- MySQL 数据表主键设计,选择自增 id 还是 UUID 还是雪花 id?
- STM32F103ZE TFT液晶代码移植
热门文章
- Windows Azure Storage (25) Azure Append Blob
- 突发!微信官方证实:“绞杀”了刷量平台
- sysdba不能远程登录,我们该怎么做 (转载)
- 如何通过参数来切换图表和数据
- Swift 3.0 预告:将 Objc 库转换成更符合 Swift 语法风格的形式
- Linux环境HBase安装配置及使用
- PostgreSQL学习笔记(1)
- 阿里巴巴连任 Java 全球管理组织席位
- Linux —— 目录(文件夹)及文件相关处理指令
- sql server 查看对象最后修改时间