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]大森林——题解相关推荐

  1. [BZOJ4573][[Zjoi2016]大森林][LCT建虚点]

    [BZOJ4573][[Zjoi2016]大森林][LCT建虚点] 题意懒得写了.... 思路: 建LCT的时候我们可以引入虚点.对于所有的1操作,新建一个没有权值的虚点,然后对于0操作,可以把新建的 ...

  2. [2019.3.20]BZOJ4573 [Zjoi2016]大森林

    发现一个重要的性质:由于不存在删点的操作,所以之后的加点并不会对之前的询问的答案造成影响. 所以我们可以先处理修改,再处理询问. 考虑从左到右扫描每一颗树,每次将前一棵树通过一些修改变为后一棵树. 发 ...

  3. BZOJ4573 : [Zjoi2016]大森林

    扫描线,从左到右依次处理每棵树. 用set按时间顺序维护影响了这棵树的所有操作,那么一个点的父亲就是它前面第一个操作1. 用Splay维护树的括号序列,那么两点间的距离就是括号数量减去匹配的括号个数. ...

  4. bzoj 4573: [Zjoi2016]大森林

    Description 小Y家里有一个大森林,里面有n棵树,编号从1到n.一开始这些树都只是树苗,只有一个节点,标号为1.这些树 都有一个特殊的节点,我们称之为生长节点,这些节点有生长出子节点的能力. ...

  5. [ZJOI2016]大森林(LCT)

    题目描述 小Y家里有一个大森林,里面有n棵树,编号从1到n.一开始这些树都只是树苗,只有一个节点,标号为1.这些树都有一个特殊的节点,我们称之为生长节点,这些节点有生长出子节点的能力. 小Y掌握了一种 ...

  6. [ZJOI2016]大森林

    Description: 小Y家里有一个大森林,里面有n棵树,编号从1到n 0 l r 表示将第 l 棵树到第 r 棵树的生长节点下面长出一个子节点,子节点的标号为上一个 0 号操作叶子标号加 1(例 ...

  7. 「ZJOI2016」大森林 解题报告

    「ZJOI2016」大森林 神仙题... 很显然线段树搞不了 考虑离线操作 我们只搞一颗树,从位置1一直往后移动,然后维护它的形态试试 显然操作0,1都可以拆成差分的形式,就是加入和删除 因为保证了操 ...

  8. 3825. 逃离大森林

    3825. 逃离大森林 题目链接 #include <bits/stdc++.h> #define x first #define y second using namespace std ...

  9. 牛客题霸 [寻找第K大] C++题解/答案

    牛客题霸 [寻找第K大] C++题解/答案 题目描述 有一个整数数组,请你根据快速排序的思路,找出数组中第K大的数. 给定一个整数数组a,同时给定它的大小n和要找的K(K在1到n之间),请返回第K大的 ...

最新文章

  1. Google Brain团队最新视频介绍
  2. NYOJ 248 BUYING FEED (贪心)
  3. ArrayBlockingQueue原理分析-remove方法
  4. 深度学习之基于Inception_ResNet_V2和CNN实现交通标志识别
  5. ssm如何支持热部署_Pipedrive如何在每天部署50+次的情况下支持质量发布?
  6. 什么是机器学习?有哪些分类?到底有什么用?终于有人讲明白了
  7. 使用ADMT3.2迁移域用户
  8. 应用迁移方案_Kubernetes如何成为迁移旧版应用程序的解决方案
  9. python2和python3共存时,设置默认python为python3
  10. multism中ui和uo应该怎么表示_第310 这四个常考英语单词,到底表示时间还是地点?...
  11. 常见排序算法之快速排序
  12. java 跨平台的等宽字体_值得推荐的优秀编程字体/代码等宽字体收集(转)
  13. 发动机冒黑烟_发动机冒黑烟的原因和解决方法
  14. 第十三届“华中杯”大学生数学建模挑战赛题目 A 题 马赛克瓷砖选色问题
  15. 概率论与数理统计学习笔记(3)——Pearson相关系数与Spearman相关系数
  16. android 11源码OTA升级封装及U盘检测
  17. Android编程制作漫画,画出自己的漫画 Android漫画风制作所
  18. 权重推送 产品定位 直通车投放 关键词 直通车人群 创意标题 补单 新手上路,直通车烧钱没效果怎么办?
  19. 发字的楷书写法图片_优秀的楷体书写作品高清图片
  20. 头脑王者服务器维护,头脑王者服务器

热门文章

  1. abaqus生成adams柔性体_专栏 | HyperMesh_To_Abaqus接口——模型导入导出问题
  2. Collection 和 Collections区别
  3. gtk/Glade编程 编译命令不成功 解决方法
  4. 模态和非模态代码_我们如何使模态可用和可访问?
  5. ui设计看的书_5本关于UI设计的书
  6. ai创造了哪些职业_关于创造职业的思考
  7. 祝大家七夕快乐,邀你源码共读,顺带发点红包
  8. Service Mesh所应对的8项挑战 1
  9. Sublime Text怎么快速建立一个html5页面模板
  10. 学习笔记DL007:Moore-Penrose伪逆,迹运算,行列式,主成分分析PCA