BZOJ4573:[ZJOI2016]大森林——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=4573
https://www.luogu.org/problemnew/show/P3348#sub
http://uoj.ac/problem/195
https://loj.ac/problem/2092
小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+5; struct data{int pos,id,from,to; }qry[N]; int n,m,fa[N],tr[N][2],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=0,w=0;char ch=0;while(!isdigit(ch)){w|=ch=='-';ch=getchar();}while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();return w?-X:X; } inline bool get(int x){return tr[fa[x]][1]==x; } inline bool isroot(int x){if(!fa[x])return 1;return tr[fa[x]][0]!=x&&tr[fa[x]][1]!=x; } inline void upt(int x){size[x]=val[x];if(tr[x][0])size[x]+=size[tr[x][0]];if(tr[x][1])size[x]+=size[tr[x][1]]; } inline void rotate(int x){int y=fa[x],z=fa[y],b=tr[y][0]==x?tr[x][1]:tr[x][0];if(z&&!isroot(y))(tr[z][0]==y?tr[z][0]:tr[z][1])=x;fa[x]=z;fa[y]=x;b?fa[b]=y:0;if(tr[y][0]==x)tr[x][1]=y,tr[y][0]=b;else tr[x][0]=y,tr[y][1]=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=0;x;y=x,x=fa[x]){splay(x);tr[x][1]=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][0])fa[tr[x][0]]=0;tr[x][0]=0;upt(x); } inline void makenode(int x){val[++sum]=x;size[sum]=x; } int main(){n=read(),m=read();cnt=1;L[cnt]=1,R[cnt]=n;id[cnt]=1;makenode(1);makenode(0);aux=sum;link(aux,id[1]);for(int i=1;i<=m;i++){int op=read();if(op==0){L[++cnt]=read(),R[cnt]=read();makenode(1);id[cnt]=sum;qry[++tot]=(data){1,i-m,sum,aux};}if(op==1){int l=read(),r=read(),x=read();l=max(l,L[x]);r=min(r,R[x]);if(l<=r){makenode(0);link(sum,aux);qry[++tot]=(data){l,i-m,sum,id[x]};qry[++tot]=(data){r+1,i-m,sum,aux};aux=sum;}}if(op==2){int l=read(),u=read(),v=read();qry[++tot]=(data){l,i,id[u],id[v]};}}memset(ans,-1,sizeof(ans));sort(qry+1,qry+tot+1,cmp);for(int i=1,p=1;i<=tot;p++){while(qry[i].pos==p){if(qry[i].id>0){ans[qry[i].id]=0;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]*2;}else{cut(qry[i].from);link(qry[i].from,qry[i].to);}i++;}}for(int i=1;i<=m;i++){if(ans[i]>=0)printf("%d\n",ans[i]);}return 0; }
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+
+++++++++++++++++++++++++++++++++++++++++++
转载于:https://www.cnblogs.com/luyouqi233/p/8483154.html
BZOJ4573:[ZJOI2016]大森林——题解相关推荐
- [BZOJ4573][[Zjoi2016]大森林][LCT建虚点]
[BZOJ4573][[Zjoi2016]大森林][LCT建虚点] 题意懒得写了.... 思路: 建LCT的时候我们可以引入虚点.对于所有的1操作,新建一个没有权值的虚点,然后对于0操作,可以把新建的 ...
- [2019.3.20]BZOJ4573 [Zjoi2016]大森林
发现一个重要的性质:由于不存在删点的操作,所以之后的加点并不会对之前的询问的答案造成影响. 所以我们可以先处理修改,再处理询问. 考虑从左到右扫描每一颗树,每次将前一棵树通过一些修改变为后一棵树. 发 ...
- BZOJ4573 : [Zjoi2016]大森林
扫描线,从左到右依次处理每棵树. 用set按时间顺序维护影响了这棵树的所有操作,那么一个点的父亲就是它前面第一个操作1. 用Splay维护树的括号序列,那么两点间的距离就是括号数量减去匹配的括号个数. ...
- bzoj 4573: [Zjoi2016]大森林
Description 小Y家里有一个大森林,里面有n棵树,编号从1到n.一开始这些树都只是树苗,只有一个节点,标号为1.这些树 都有一个特殊的节点,我们称之为生长节点,这些节点有生长出子节点的能力. ...
- [ZJOI2016]大森林(LCT)
题目描述 小Y家里有一个大森林,里面有n棵树,编号从1到n.一开始这些树都只是树苗,只有一个节点,标号为1.这些树都有一个特殊的节点,我们称之为生长节点,这些节点有生长出子节点的能力. 小Y掌握了一种 ...
- [ZJOI2016]大森林
Description: 小Y家里有一个大森林,里面有n棵树,编号从1到n 0 l r 表示将第 l 棵树到第 r 棵树的生长节点下面长出一个子节点,子节点的标号为上一个 0 号操作叶子标号加 1(例 ...
- 「ZJOI2016」大森林 解题报告
「ZJOI2016」大森林 神仙题... 很显然线段树搞不了 考虑离线操作 我们只搞一颗树,从位置1一直往后移动,然后维护它的形态试试 显然操作0,1都可以拆成差分的形式,就是加入和删除 因为保证了操 ...
- 3825. 逃离大森林
3825. 逃离大森林 题目链接 #include <bits/stdc++.h> #define x first #define y second using namespace std ...
- 牛客题霸 [寻找第K大] C++题解/答案
牛客题霸 [寻找第K大] C++题解/答案 题目描述 有一个整数数组,请你根据快速排序的思路,找出数组中第K大的数. 给定一个整数数组a,同时给定它的大小n和要找的K(K在1到n之间),请返回第K大的 ...
最新文章
- Google Brain团队最新视频介绍
- NYOJ 248 BUYING FEED (贪心)
- ArrayBlockingQueue原理分析-remove方法
- 深度学习之基于Inception_ResNet_V2和CNN实现交通标志识别
- ssm如何支持热部署_Pipedrive如何在每天部署50+次的情况下支持质量发布?
- 什么是机器学习?有哪些分类?到底有什么用?终于有人讲明白了
- 使用ADMT3.2迁移域用户
- 应用迁移方案_Kubernetes如何成为迁移旧版应用程序的解决方案
- python2和python3共存时,设置默认python为python3
- multism中ui和uo应该怎么表示_第310 这四个常考英语单词,到底表示时间还是地点?...
- 常见排序算法之快速排序
- java 跨平台的等宽字体_值得推荐的优秀编程字体/代码等宽字体收集(转)
- 发动机冒黑烟_发动机冒黑烟的原因和解决方法
- 第十三届“华中杯”大学生数学建模挑战赛题目 A 题 马赛克瓷砖选色问题
- 概率论与数理统计学习笔记(3)——Pearson相关系数与Spearman相关系数
- android 11源码OTA升级封装及U盘检测
- Android编程制作漫画,画出自己的漫画 Android漫画风制作所
- 权重推送 产品定位 直通车投放 关键词 直通车人群 创意标题 补单 新手上路,直通车烧钱没效果怎么办?
- 发字的楷书写法图片_优秀的楷体书写作品高清图片
- 头脑王者服务器维护,头脑王者服务器
热门文章
- abaqus生成adams柔性体_专栏 | HyperMesh_To_Abaqus接口——模型导入导出问题
- Collection 和 Collections区别
- gtk/Glade编程 编译命令不成功 解决方法
- 模态和非模态代码_我们如何使模态可用和可访问?
- ui设计看的书_5本关于UI设计的书
- ai创造了哪些职业_关于创造职业的思考
- 祝大家七夕快乐,邀你源码共读,顺带发点红包
- Service Mesh所应对的8项挑战 1
- Sublime Text怎么快速建立一个html5页面模板
- 学习笔记DL007:Moore-Penrose伪逆,迹运算,行列式,主成分分析PCA