P3721 [AH2017/HNOI2017]单旋
题目:https://www.luogu.org/problemnew/show/P3721
手玩一下即可AC此题。
结论:插入x后,x要么会成为x的前驱的右儿子,要么成为x的后继的左儿子,这取决于它的前驱和后继的深度。
证明:首先可以证明的是,x的前驱和后继一定存在祖先与后代的关系,因为如果不存在此关系,它们的LCA一定和双方更接近。
然后这个结论画画图就比较显然了。
结论:单旋删除最小值后,它连向根节点的这条路径不发生变化,手玩即可证明,改变的只有它的儿子。
那么这个题就显然可以用LCT来维护,查询深度也很简单。
#include<iostream>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<set>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#define N 330000
#define L 300000
#define eps 1e-7
#define inf 1e9+7
#define db double
#define ll long long
#define ldb long double
using namespace std;
inline int read()
{
char ch=0;
int x=0,flag=1;
while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*flag;
}
#define lson son[x][0]
#define rson son[x][1]
int root,v[N],f[N],st[N],flag[N],sumv[N],son[N][2];
void pushup(int x){sumv[x]=sumv[lson]+sumv[rson]+1;}
void update(int x){flag[x]^=1;swap(lson,rson);}
void pushdown(int x){if(!flag[x])return;if(lson)update(lson);if(rson)update(rson);flag[x]=0;}
bool get(int x){return son[f[x]][1]==x;}
bool isroot(int x){return (son[f[x]][0]!=x)&&(son[f[x]][1]!=x);}
void rotate(int x)
{
int y=f[x],z=f[y],tx=get(x),ty=get(y),p=son[x][!tx];
if(!isroot(y))son[z][ty]=x;son[x][!tx]=y;son[y][tx]=p;
if(p)f[p]=y;f[y]=x;f[x]=z;pushup(y);pushup(x);
}
void splay(int x)
{
int cnt=0,tmp=x;
st[++cnt]=x;
while(!isroot(x))st[++cnt]=f[x],x=f[x];
for(int i=cnt;i>=1;i--)pushdown(st[i]);
x=tmp;
while(!isroot(x))
{
int y=f[x];
if(!isroot(y))rotate(get(x)==get(y)?y:x);
rotate(x);
}
pushup(x);
}
void access(int x){for(int y=0;x;y=x,x=f[x])splay(x),son[x][1]=y,pushup(x);}
void makeroot(int x){access(x);splay(x);update(x);}
void link(int x,int y){if(!x||!y)return;makeroot(x);f[x]=y;}
void cut(int x,int y){if(!x||!y)return;makeroot(x);access(y);splay(y);f[x]=son[y][0]=0;pushup(y);}
int dep(int x){makeroot(root);access(x);splay(x);return sumv[x];}
set<int>S;
set<int>::iterator it;
int opt[N],w[N],W[N],fa[N],lc[N],rc[N];
int main()
{
int m=read(),num=0;
for(int i=1;i<=m;i++)
{
opt[i]=read();
if(opt[i]==1)w[i]=W[++num]=read();
}
sort(W+1,W+num+1);num=unique(W+1,W+num+1)-W-1;
for(int i=1;i<=m;i++)if(opt[i]==1)w[i]=lower_bound(W+1,W+num+1,w[i])-W;
for(int i=1;i<=m;i++)
{
lc[0]=rc[0]=fa[0]=fa[root]=0;
int flag=opt[i];
if(flag==1)
{
int x=w[i],p,q;
S.insert(x);it=S.find(x);
if(it==S.begin())p=-1;else p=*(--S.lower_bound(x));
if(it==(--S.end()))q=-1;else q=*(S.upper_bound(x));
if(p==-1&&q==-1){root=x;printf("1\n");continue;}
if(p==-1||dep(p)<dep(q))link(x,q),lc[q]=x,fa[x]=q;
else link(x,p),rc[p]=x,fa[x]=p;
printf("%d\n",dep(x));
}
if(flag==2||flag==4)
{
int x=*S.begin(),p=rc[x],q=fa[x];
printf("%d\n",dep(x));
if(x!=root)
{
cut(x,p);cut(x,q);link(p,q);link(x,root);
lc[q]=p;if(p)fa[p]=q;rc[x]=root;fa[x]=0;fa[root]=x;root=x;
}
}
if(flag==3||flag==5)
{
int x=*S.rbegin(),p=lc[x],q=fa[x];
printf("%d\n",dep(x));
if(x!=root)
{
cut(x,p);cut(x,q);link(p,q);link(x,root);
rc[q]=p;if(p)fa[p]=q;lc[x]=root;fa[x]=0;fa[root]=x;root=x;
}
}
if(flag==4)
{
int x=*S.begin(),p=rc[x];
if(p)cut(x,p),rc[x]=fa[p]=0;
root=p;S.erase(x);
}
if(flag==5)
{
int x=*S.rbegin(),p=lc[x];
if(p)cut(x,p),lc[x]=fa[p]=0;
root=p;S.erase(x);
}
}
return 0;
}
P3721 [AH2017/HNOI2017]单旋的更多相关文章
- 洛谷 P3721 - [AH2017/HNOI2017]单旋(LCT)
洛谷题面传送门 终于调出来这道题了,写篇题解( 首先碰到这样的题我们肯定要考虑每种操作会对树的形态产生怎样的影响: 插入操作:对于 BST 有一个性质是,当你插入一个节点时,其在 BST 上的父亲肯定 ...
- luogu P3721 [AH2017/HNOI2017]单旋
传送门 \(Spaly:\)??? 考虑在暴力模拟的基础上优化 如果要插入一个数,那么根据二叉查找树的性质,这个点一定插在他的前驱的右子树或者是后继的左子树,可以利用set维护当前树里面的数,方便查找 ...
- 洛谷P3721 [AH2017/HNOI2017]单旋(线段树 set spaly)
题意 题目链接 Sol 这题好毒瘤啊.. 首先要观察到几个性质: 将最小值旋转到根相当于把右子树变为祖先的左子树,然后将原来的根变为当前最小值 上述操作对深度的影响相当于右子树不变,其他的位置-1 然 ...
- [AH2017/HNOI2017]单旋
题目 \(\rm splay\)水平太差,于是得手玩一下才能发现规律 首先插入一个数,其肯定会成为其前驱的右儿子或者是后继的左儿子,进一步手玩发现前驱的右儿子或者是后继的左儿子一定只有一个是空的,我们 ...
- [AH2017/HNOI2017] 单旋 - Splay
Splay 暴力维护节点信息即可 #include<iostream> #include<cstdio> #include<cstring> #include< ...
- bzoj 4825: [Hnoi2017]单旋 [lct]
4825: [Hnoi2017]单旋 题意:有趣的spaly hnoi2017刚出来我就去做,当时这题作死用了ett,调了5节课没做出来然后发现好像直接用lct就行了然后弃掉了... md用lct不知 ...
- 【LG3721】[HNOI2017]单旋
[LG3721][HNOI2017]单旋 题面 洛谷 题解 20pts 直接模拟\(spaly\)的过程即可. 100pts 可以发现单旋最大.最小值到根,手玩是有显然规律的,发现只需要几次\(lin ...
- 4825: [Hnoi2017]单旋
4825: [Hnoi2017]单旋 链接 分析: 以后采取更保险的方式写代码!!!81行本来以为不特判也可以,然后就总是比答案大1,甚至出现负数,调啊调啊调啊调~~~ 只会旋转最大值和最小值,以最小 ...
- [BZOJ4825][HNOI2017]单旋(线段树+Splay)
4825: [Hnoi2017]单旋 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 667 Solved: 342[Submit][Status][ ...
随机推荐
- 【系列教程1】Gradle入门系列二:第一个Java项目
这篇教程的主要内容是讲解如何用Gradle编译和打包一个简单的Java项目. 该Java项目只有一个需求:我们的构建脚本必须创建一个可执行的Jar文件,换句话说,我们必须能够使用命令java -jar ...
- BZOJ2956: 模积和
Description 求∑∑((n mod i)*(m mod j))其中1<=i<=n,1<=j<=m,i≠j. Input 第一行两个数n,m. Output 一个整数表 ...
- 深度学习课程笔记(三)Backpropagation 反向传播算法
深度学习课程笔记(三)Backpropagation 反向传播算法 2017.10.06 材料来自:http://speech.ee.ntu.edu.tw/~tlkagk/courses_MLDS1 ...
- (转载)Navicat Premium 12.1.16.0安装与激活
声明:本文所提供的所有软件均来自于互联网,仅供个人研究和学习使用,请勿用于商业用途,下载后请于24小时内删除,请支持正版! 本文介绍Navicat Premium 12的安装.激活与基本使用.已于20 ...
- 解决Linux服务器磁盘空间不足的问题
在linux服务器执行程序时报错: awk: write failure (No space left on device)awk: close failed on file /dev/stdout ...
- HDU 5727 Necklace(全排列+二分图匹配)
http://acm.split.hdu.edu.cn/showproblem.php?pid=5727 题意:现在有n个阳珠子和n个阴珠子,现在要把它们串成项链,要求是阴阳珠子间隔串,但是有些阴阳珠 ...
- windows下远程连接Mysql
使用“Ctrl + R”组合键快速打开cmd窗口,并输入“cmd”命令,打开cmd窗口. 使用“mysql -uroot -proot”命令可以连接到本地的mysql服务. 使用“use mysql” ...
- C#深入多线程
主线程: th = Thread.CurrentThread; //现在的线程为主线程 th.Name = "MainThread"; //set线程名字:主线程本身没有名字 th ...
- 后台返回数据判断是http还是后台本地图片 indexOf
今天的笔记呢,记录一下 其实这个应该后台去判断的,但是因为某种原因,今天我们前台做一下判断 事情是这样的,后台返回我一个url 这个url有的http开头的 也有他后台本地的例如:/img/1.pn ...
- 前端开发——HTML学习笔记
HTML03