BZOJ

LOJ

洛谷


这题不难啊,我怎么就那么傻,拿随便一个节点去模拟。。

我们只需要能够维护,将最小值或最大值转到根。模拟一下发现,对于最小值,它的右子树深度不变(如果存在),其余节点深度全部\(+1\),且除右儿子外所有点的父子关系不会改变。最大值同理。

因为右子树和右子树外的所有点的值域是连续的,所以按值域为下标维护线段树,区间加即可。

至于怎么维护右子树的范围?不就是\((val_x,val_{fa[x]})\)吗。。

如果是删除,把它转到根后,对所有点深度\(-1\)即可。

考虑如何插入。插入的位置肯定是它的前驱后继之间啊。所以用set或此时的线段树找到前驱后继,在对应位置插入就行了(线段树似乎有些麻烦)。然后在线段树上更新一下\(dep\)。


//7276kb	824ms
#include <set>
#include <cstdio>
#include <cctype>
#include <algorithm>
#define mp std::make_pair
#define pr std::pair<int,int>
//#define gc() getchar()
#define MAXIN 300000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
const int N=1e5+5; int n,root,val[N],ref[N],fa[N],son[N][2],opt[N];
std::set<int> st;
char IN[MAXIN],*SS=IN,*TT=IN;
struct Segment_Tree
{
#define ls rt<<1
#define rs rt<<1|1
#define lson l,m,ls
#define rson m+1,r,rs
#define S N<<2
int val[S];
#undef S
#define Upd(rt,v) val[rt]+=v
// #define Update(rt) exist[rt]=exist[ls]||exist[rs]
inline void PushDown(int rt)
{
Upd(ls,val[rt]), Upd(rs,val[rt]), val[rt]=0;
}
void Modify(int l,int r,int rt,int L,int R,int v)
{
if(L<=l && r<=R) {Upd(rt,v); return;}
if(val[rt]) PushDown(rt);
int m=l+r>>1;
if(L<=m) Modify(lson,L,R,v);
if(m<R) Modify(rson,L,R,v);
}
void Set(int l,int r,int rt,int p,int v)
{
while(l!=r)
{
if(val[rt]) PushDown(rt);
int m=l+r>>1;
p<=m ? (r=m,rt=ls) : (l=m+1,rt=rs);
}
val[rt]=v;
}
int Query(int l,int r,int rt,int p)
{
while(l!=r)
{
if(val[rt]) PushDown(rt);
int m=l+r>>1;
p<=m ? (r=m,rt=ls) : (l=m+1,rt=rs);
}
return val[rt];
}
pr Query2(int l,int r,int rt,int p)
{
while(l!=r)
{
if(val[rt]) PushDown(rt);
int m=l+r>>1;
p<=m ? (r=m,rt=ls) : (l=m+1,rt=rs);
}
return mp(rt,val[rt]);
}
}T; inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-48,c=gc());
return now;
}
inline int Find(int x)
{
int l=1,r=n,mid;
while(l<r)
if(ref[mid=l+r>>1]<x) l=mid+1;
else r=mid;
return l;
}
#define S 1,n,1
int Insert(int x)
{
if(st.empty()) {st.insert(root=x), T.Set(S,x,1); return 1;}
std::set<int>::iterator it=st.upper_bound(x);
int p,v;
if(it!=st.end()&&!son[*it][0]) son[p=*it][0]=x;
else son[p=*(--it)][1]=x;
st.insert(x), fa[x]=p, T.Set(S,x,v=T.Query(S,p)+1);
return v;
}
int RotateMin()
{
int x=*st.begin();
if(!fa[x]) return 1;
pr v=T.Query2(S,x);
T.Modify(S,fa[x],n,1), T.val[v.first]=1;//T.Set(S,x,1);
son[fa[x]][0]=son[x][1], fa[son[x][1]]=fa[x], fa[x]=0;
son[x][1]=root, fa[root]=x, root=x;
return v.second;
}
int RotateMax()
{
int x=*st.rbegin();
if(!fa[x]) return 1;
pr v=T.Query2(S,x);
T.Modify(S,1,fa[x],1), T.val[v.first]=1;//T.Set(S,x,1);
son[fa[x]][1]=son[x][0], fa[son[x][0]]=fa[x], fa[x]=0;
son[x][0]=root, fa[root]=x, root=x;
return v.second;
}
int DeleteMin()
{
int v=RotateMin(),x=*st.begin();
st.erase(x), T.Modify(S,1,n,-1), fa[root=son[x][1]]=0, son[x][1]=0;
return v;
}
int DeleteMax()
{
int v=RotateMax(),x=*st.rbegin();
st.erase(x), T.Modify(S,1,n,-1), fa[root=son[x][0]]=0, son[x][0]=0;
return v;
} int main()
{
// freopen("splay.in","r",stdin);
// freopen("splay.out","w",stdout); const int Q=read(); int n=0;
for(int i=1; i<=Q; ++i)
if((opt[i]=read())==1) ++n, val[n]=ref[n]=read();
std::sort(ref+1,ref+1+n), ::n=n;
for(int i=1,t=0; i<=Q; ++i)
switch(opt[i])
{
case 1: printf("%d\n",Insert(Find(val[++t]))); break;
case 2: printf("%d\n",RotateMin()); break;
case 3: printf("%d\n",RotateMax()); break;
case 4: printf("%d\n",DeleteMin()); break;
case 5: printf("%d\n",DeleteMax()); break;
}
return 0;
}

BZOJ.4825.[AHOI/HNOI2017]单旋(线段树)的更多相关文章

  1. [BZOJ4825][HNOI2017]单旋(线段树+Splay)

    4825: [Hnoi2017]单旋 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 667  Solved: 342[Submit][Status][ ...

  2. 【BZOJ4825】[Hnoi2017]单旋 线段树+set

    [BZOJ4825][Hnoi2017]单旋 Description H 国是一个热爱写代码的国家,那里的人们很小去学校学习写各种各样的数据结构.伸展树(splay)是一种数据结构,因为代码好写,功能 ...

  3. 【bzoj4825】[Hnoi2017]单旋 线段树+STL-set

    题目描述 H 国是一个热爱写代码的国家,那里的人们很小去学校学习写各种各样的数据结构.伸展树(splay)是一种数据结构,因为代码好写,功能多,效率高,掌握这种数据结构成为了 H 国的必修技能.有一天 ...

  4. 洛谷P3721 [AH2017/HNOI2017]单旋(线段树 set spaly)

    题意 题目链接 Sol 这题好毒瘤啊.. 首先要观察到几个性质: 将最小值旋转到根相当于把右子树变为祖先的左子树,然后将原来的根变为当前最小值 上述操作对深度的影响相当于右子树不变,其他的位置-1 然 ...

  5. bzoj 4825: [Hnoi2017]单旋 [lct]

    4825: [Hnoi2017]单旋 题意:有趣的spaly hnoi2017刚出来我就去做,当时这题作死用了ett,调了5节课没做出来然后发现好像直接用lct就行了然后弃掉了... md用lct不知 ...

  6. 4825: [Hnoi2017]单旋

    4825: [Hnoi2017]单旋 链接 分析: 以后采取更保险的方式写代码!!!81行本来以为不特判也可以,然后就总是比答案大1,甚至出现负数,调啊调啊调啊调~~~ 只会旋转最大值和最小值,以最小 ...

  7. 【LG3721】[HNOI2017]单旋

    [LG3721][HNOI2017]单旋 题面 洛谷 题解 20pts 直接模拟\(spaly\)的过程即可. 100pts 可以发现单旋最大.最小值到根,手玩是有显然规律的,发现只需要几次\(lin ...

  8. BZOJ:4825: [Hnoi2017]单旋

    Description H 国是一个热爱写代码的国家,那里的人们很小去学校学习写各种各样的数据结构.伸展树(splay)是一种数据结构,因为代码好写,功能多,效率高,掌握这种数据结构成为了 H 国的必 ...

  9. 【刷题】BZOJ 4825 [Hnoi2017]单旋

    Description H 国是一个热爱写代码的国家,那里的人们很小去学校学习写各种各样的数据结构.伸展树(splay)是一种数据结构,因为代码好写,功能多,效率高,掌握这种数据结构成为了 H 国的必 ...

随机推荐

  1. Best Free Hacking E-Books 2017 In PDF Format

    1.Best Free Hacking E-Books 2017 In PDF Format: 电子书籍下载地址 后续我会更新在我的百度云资源 上,需要的留言Black Belt Hacking &a ...

  2. CF1065D

    如果不喜欢过长代码的看官,请移步其他题解... 这题其实思想极其简单: 棋盘问题常见的算法都比较暴力,常用的有搜索和状压dp 而这道题显然没啥能状压的,所以我们考虑搜索 但是仅仅搜索是不够的,因为有极 ...

  3. win+python+selenium实现窗口和tab切换

    这篇总结主要是关于两方面的需求:其一,在浏览器不同tab标签页之间按时间切换(同事用来不停刷新grid crontol 监控页面):其二,实现开启多个窗口,并将窗口缩放到一定范围,并齐占满整个桌面,按 ...

  4. 一张图看懂JVM之垃圾回收算法详解

    导读                                                                                                  ...

  5. python之字符编码

    1.以什么编码存的就以什么编码取出; 内存固定使用unicode编码; 我们可以控制的编码是往硬盘存放或者基于网络传输选择编码. 2.数据是最先产生于内存中,是unicode格式,要想传输需要转成by ...

  6. 去掉A标签的点击选中边框

    非IE a:focus { outline:none; }

  7. pycaffe训练的完整组件示例

    pycaffe训练的完整组件示例 为什么写这篇博客 1. 需要用到pycaffe 因为用到的开源代码基于Caffe:要维护的项目基于Caffe.基本上是用Caffe的Python接口. 2. 训练中想 ...

  8. Win10任务栏通知区域上已卸载程序无效图标选项如何清除?

    在Win10系统中,大部分用户都已经知道在“选择在任务栏上显示哪些图标”来让一些软年图标显示,一些隐藏,不过使用Win10系统久了之后发现,在设置通知区域图标中有很多已经卸载程序的无效选项!这让设置时 ...

  9. 435. Non-overlapping Intervals

    Given a collection of intervals, find the minimum number of intervals you need to remove to make the ...

  10. 在IDEA中编写Spark的WordCount程序

    1:spark shell仅在测试和验证我们的程序时使用的较多,在生产环境中,通常会在IDE中编制程序,然后打成jar包,然后提交到集群,最常用的是创建一个Maven项目,利用Maven来管理jar包 ...