BZOJ4573:[ZJOI2016]大森林——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=4573
https://www.luogu.org/problemnew/show/P3348#sub
小Y家里有一个大森林,里面有n棵树,编号从1到n。一开始这些树都只是树苗,只有一个节点,标号为1。这些树都有一个特殊的节点,我们称之为生长节点,这些节点有生长出子节点的能力。
小Y掌握了一种魔法,能让第l棵树到第r棵树的生长节点长出一个子节点。同时她还能修改第l棵树到第r棵树的生长节点。她告诉了你她使用魔法的记录,你能不能管理她家的森林,并且回答她的询问呢?
参考:http://www.sigongzi.org/index.php/archives/LOJ2092.html
思路:
显然我们不能对每棵树LCT维护一下,而且我们对于这棵树的形态还很严格。
那么我们把前一棵树的形态转换为后一棵树的形态,这样就只需要一棵树了。
先考虑对于0操作,实际上我们可以记录每个时刻每个节点在哪一段区间中(代码的L和R就是干这个的),所以我们大可以对所有的树都进行0操作。
对于1操作,和0操作类似,用L和R更新l和r后进行操作。
然后为了能够快捷的更新树,我们建立一个size为0的虚点(这样对于路径长度就不需要修改了),所有的生长操作都在上面进行,这样我们删除的时候cut这个点即可。
对于2操作,事实上两个点一定存在的话,完全可以让0和1操作全部排到它的前面。
实现:
先把所有操作存下来,然后以操作的树为第一关键字,操作编号和顺序为第二关键字排序。
(对于区间修改思考差分,毕竟我们都是对同一棵树操作的。)
然后按树编号从左到右进行操作,对于0和1操作先对虚点清空然后长即可。
查询的时候就是用LCA求最短路的方法一样。
- #include<algorithm>
- #include<iostream>
- #include<cstring>
- #include<cctype>
- #include<cstdio>
- #include<vector>
- #include<queue>
- #include<cmath>
- using namespace std;
- const int N=4e5+;
- struct data{
- int pos,id,from,to;
- }qry[N];
- int n,m,fa[N],tr[N][],val[N],size[N];
- int cnt,tot,sum,aux,L[N],R[N],id[N],ans[N];
- inline bool cmp(data a,data b){
- return a.pos<b.pos||(a.pos==b.pos&&a.id<b.id);
- }
- inline int read(){
- int X=,w=;char ch=;
- while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
- while(isdigit(ch))X=(X<<)+(X<<)+(ch^),ch=getchar();
- return w?-X:X;
- }
- inline bool get(int x){
- return tr[fa[x]][]==x;
- }
- inline bool isroot(int x){
- if(!fa[x])return ;
- return tr[fa[x]][]!=x&&tr[fa[x]][]!=x;
- }
- inline void upt(int x){
- size[x]=val[x];
- if(tr[x][])size[x]+=size[tr[x][]];
- if(tr[x][])size[x]+=size[tr[x][]];
- }
- inline void rotate(int x){
- int y=fa[x],z=fa[y],b=tr[y][]==x?tr[x][]:tr[x][];
- if(z&&!isroot(y))(tr[z][]==y?tr[z][]:tr[z][])=x;
- fa[x]=z;fa[y]=x;b?fa[b]=y:;
- if(tr[y][]==x)tr[x][]=y,tr[y][]=b;
- else tr[x][]=y,tr[y][]=b;
- upt(y);upt(x);
- }
- inline void splay(int x){
- while(!isroot(x)){
- if(!isroot(fa[x]))
- rotate((get(x)==get(fa[x])?fa[x]:x));
- rotate(x);
- }
- upt(x);
- }
- inline int access(int x){
- int y;
- for(y=;x;y=x,x=fa[x]){
- splay(x);tr[x][]=y;
- if(y)fa[y]=x;
- }
- return y;
- }
- inline void link(int x,int y){
- splay(y);fa[x]=y;
- }
- inline void cut(int x){
- access(x);splay(x);
- if(tr[x][])fa[tr[x][]]=;
- tr[x][]=;upt(x);
- }
- inline void makenode(int x){
- val[++sum]=x;size[sum]=x;
- }
- int main(){
- n=read(),m=read();
- cnt=;L[cnt]=,R[cnt]=n;id[cnt]=;
- makenode();makenode();
- aux=sum;
- link(aux,id[]);
- for(int i=;i<=m;i++){
- int op=read();
- if(op==){
- L[++cnt]=read(),R[cnt]=read();
- makenode();
- id[cnt]=sum;
- qry[++tot]=(data){,i-m,sum,aux};
- }
- if(op==){
- int l=read(),r=read(),x=read();
- l=max(l,L[x]);r=min(r,R[x]);
- if(l<=r){
- makenode();
- link(sum,aux);
- qry[++tot]=(data){l,i-m,sum,id[x]};
- qry[++tot]=(data){r+,i-m,sum,aux};
- aux=sum;
- }
- }
- if(op==){
- int l=read(),u=read(),v=read();
- qry[++tot]=(data){l,i,id[u],id[v]};
- }
- }
- memset(ans,-,sizeof(ans));
- sort(qry+,qry+tot+,cmp);
- for(int i=,p=;i<=tot;p++){
- while(qry[i].pos==p){
- if(qry[i].id>){
- ans[qry[i].id]=;
- access(qry[i].from);splay(qry[i].from);
- ans[qry[i].id]+=size[qry[i].from];
- int lca=access(qry[i].to);
- splay(qry[i].to);
- ans[qry[i].id]+=size[qry[i].to];
- access(lca);splay(lca);ans[qry[i].id]-=size[lca]*;
- }
- else{
- cut(qry[i].from);link(qry[i].from,qry[i].to);
- }
- i++;
- }
- }
- for(int i=;i<=m;i++){
- if(ans[i]>=)printf("%d\n",ans[i]);
- }
- return ;
- }
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+
+++++++++++++++++++++++++++++++++++++++++++
BZOJ4573:[ZJOI2016]大森林——题解的更多相关文章
- BZOJ4573 : [Zjoi2016]大森林
扫描线,从左到右依次处理每棵树. 用set按时间顺序维护影响了这棵树的所有操作,那么一个点的父亲就是它前面第一个操作1. 用Splay维护树的括号序列,那么两点间的距离就是括号数量减去匹配的括号个数. ...
- [BZOJ4573][ZJOI2016]大♂森林
bzoj luogu uoj sol \(orz\ \ HJT\ \ dalao\)教会我做这道题. 考虑每两个相邻位置的树的差异. 对于一个1操作(更换生长节点),假设区间是\([l,r]\),那么 ...
- [ZJOI2016]大森林(LCT)
题目描述 小Y家里有一个大森林,里面有n棵树,编号从1到n.一开始这些树都只是树苗,只有一个节点,标号为1.这些树都有一个特殊的节点,我们称之为生长节点,这些节点有生长出子节点的能力. 小Y掌握了一种 ...
- bzoj 4573: [Zjoi2016]大森林
Description 小Y家里有一个大森林,里面有n棵树,编号从1到n.一开始这些树都只是树苗,只有一个节点,标号为1.这些树 都有一个特殊的节点,我们称之为生长节点,这些节点有生长出子节点的能力. ...
- P3348 [ZJOI2016]大森林
\(\color{#0066ff}{ 题目描述 }\) 小Y家里有一个大森林,里面有n棵树,编号从1到n.一开始这些树都只是树苗,只有一个节点,标号为1.这些树都有一个特殊的节点,我们称之为生长节点, ...
- [ZJOI2016]大森林
Description: 小Y家里有一个大森林,里面有n棵树,编号从1到n 0 l r 表示将第 l 棵树到第 r 棵树的生长节点下面长出一个子节点,子节点的标号为上一个 0 号操作叶子标号加 1(例 ...
- 【刷题】BZOJ 4573 [Zjoi2016]大森林
Description 小Y家里有一个大森林,里面有n棵树,编号从1到n.一开始这些树都只是树苗,只有一个节点,标号为1.这些树都有一个特殊的节点,我们称之为生长节点,这些节点有生长出子节点的能力.小 ...
- 【LuoguP3348】[ZJOI2016]大森林
题目链接 题目描述 小Y家里有一个大森林,里面有n棵树,编号从1到n.一开始这些树都只是树苗,只有一个节点,标号为1.这些树都有一个特殊的节点,我们称之为生长节点,这些节点有生长出子节点的能力. 小Y ...
- 【BZOJ4573】[ZJOI2016] 大森林(LCT)
点此看题面 大致题意: 有\(n\)棵树,初始各有\(1\)个编号为\(1\)的节点,且其为生长节点.\(3\)种操作:将\([l,r]\)区间内的树增加一个新的编号的节点,修改\([l,r]\)区间 ...
随机推荐
- 转:Docker创建centos的LNMP镜像
转自:http://www.vckai.com/p/29 1. 安装docker 这个就不说了,不会的可以看下我之前的文章<Docker介绍及安装>. 1)启动docker # serv ...
- Unity Container中的几种注册方式与示例
1.实例注册 最简单的注册方式就是实例注册,Unity 容器负责维护对一个类型的单例引用,比如: 有如下的实际类型: namespace ConsoleSample { public class Sa ...
- js函数相关高级用法
一.惰性载入函数(lazy function) 使用场景:当一个函数中的判断分支只用执行一次(第一次调用时执行),后续不会再变化,则可以使用惰性函数来提高性能. var addEvent = func ...
- JAVA日志框架概述
日志用来记录应用的运行状态以及一些关键业务信息,其重要性不言而喻,通常我们借助于现有的日志框架完成日志输出.目前开源的日志框架很多,常见的有log4j.logback等,有时候我们还会 ...
- MySQL数据库优化方法
一.表类型MyISAM 和 InnoDB的区别 作者:Oscarwin链接:https://www.zhihu.com/question/20596402/answer/211492971来源:知乎著 ...
- 用Anko和Kotlin实现Android上的对话框和警告提示(KAD 24)
作者:Antonio Leiva 时间:Mar 9, 2017 原文链接:https://antonioleiva.com/dialogs-android-anko-kotlin/ 借助Builder ...
- 第二章 IP协议详解
第二章 IP协议详解 2.1 IP服务的特点 它为上层协议提供了无状态,无连接,不可靠的服务 名称 简介 优点 缺点 对付缺点的方法 无状态 IP通信双方不同步传输数据的状态信息 无须为保持通信的状态 ...
- TensorFlow | ReluGrad input is not finite. Tensor had NaN values
问题的出现 Question 这个问题是我基于TensorFlow使用CNN训练MNIST数据集的时候遇到的.关键的相关代码是以下这部分: cross_entropy = -tf.reduce_sum ...
- iOS-【UIDynamic-UIKit动力学】
如果看不到图片 可以尝试更换浏览器(推荐Safari ) 0.了解 •Dynamic Animator:动画者,为动力学元素提供物理学相关的能力及动画,同时为这些元素提供相关的上下文,是动力学元素与底 ...
- html .net 网页,网站标题添图标
<link rel="icon" href="../favicon.ico" type="image/x-icon" /> &l ...