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. bzoj 3529

    非常好的一道莫比乌斯反演题,对提升自己的能力有很大帮助. 首先我们分析一下题意:题意让我们求,其中 那么我们首先对后面的式子进行一下变形,变形过程详见https://blog.csdn.net/lle ...

  2. java常用的中间件

    tomcatWeblogicJBOSSColdfusionWebsphereGlassFish 一般本地开发的话建议使用tomcat. linux系统建议使用jetty或apache hpptd 大型 ...

  3. vue 在.vue文件里监听路由

    监听路由  watch   $route vue项目中的App.vue 文件 <template> <div id="app"> <!--includ ...

  4. 谷歌、火狐浏览器 缩放为80% 时,margin值才正确

    声明:小白的笔记,欢迎大神指点.联系QQ:1522025433. 在网页布局中,通过 谷歌浏览器或火狐浏览器 预览时,发现我们定义的盒模型width,height,margin,padding 值都是 ...

  5. Idea和PyCharm激活破解

    1. 先去百度去官网下载专业版IDE, Idea 和PyCharm激活方法一样 2. 下载破解包, 点击下载 3. 将下载的jar包放到这个安装目录的bin目录下面 4. 在bin目录下面的文件pyc ...

  6. nodejs 环境安装

    参考网站 http://www.runoob.com/nodejs/nodejs-http-server.html https://github.com/nodesource/distribution ...

  7. CentOS6安装Zabbix4.0

    安装依赖包yum install net-snmp-devel libevent-devel libxml2-devel curl-devel libjpeg-devel libpng-devel l ...

  8. JSP基础知识➣获取参数和过滤器(四)

    JSP表单提交和参数获取 JSP表单提交的两种方式:post和get,通过这两种方式提交的参数到后台,获取参数的值主要由request来处理,获取值的方式有以下几种: getParameter():  ...

  9. python基础——dict和set(字典和集合)

    1.dict:pop(),get(),in,{} >>> dicttest = {'marry':34,'jucy':56} --初始化>>> dicttest{' ...

  10. Eclipse的properties文件中文乱码解决方法

    转自:http://jingyan.baidu.com/article/ed2a5d1f3381d709f6be17f8.html 打开Myeclipse,找到window这一栏,点击Preferen ...