题目描述

网址:https://www.luogu.org/problemnew/show/3721
大意:
有一颗单旋Splay(Spaly),以key值为优先度,总共有5个操作。

  • [1] 插入一个节点,需返还插入后此节点的深度。
  • [2] 把最小点单旋到根,需要返还旋转前此点深度。
  • [3] 把最大点单旋到根,需要返还旋转前此点深度。
  • [4] 把最小点单旋到根,然后删除根,需要返还旋转前此点深度。
  • [5] 把最大点单旋到根,然后删除根,需要返还旋转前此点深度。
    总共有M个操作,数据范围:M <= 100000

题目解法

题目提出的为splay算法,那么正解肯定不是splay。
观察到所有旋转操作都是对极值进行操作的,又是单旋,手玩一下就会发现树的形态基本不改变。
所以,我们可以建立一棵普通二叉树,由于每次修改的点都为常数个。
所以对于修改操作,手动修改即可。
然后考虑查询深度的问题,可以用LCT维护,修改普通二叉树对应的Link、Cut即可维持树的形态。
用LCT查询点u的深度,只需要把u到root的路径变为重路径,查询这棵辅助树的大小即可
最后是插入操作。用set可快速查询前驱与后继。
可以发现一定是插在两者中深度较大的下面,与前面一样直接修改即可。

实现代码

#include<bits/stdc++.h>
#define ll long long
#define RG register
#define IL inline
#define ls(x) ch[x][0]
#define rs(x) ch[x][1]
#define maxn 210000
using namespace std;

IL int gi(){  RG int date = 0, m = 1;  RG char ch = 0;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch = getchar();
        if(ch == '-'){m = -1; ch = getchar();}
    while(ch>='0' && ch<='9')
           {date=date*10+ch-'0'; ch = getchar();}
        return date*m;
}

int root,cnt,M;
int Stk[maxn],ch[maxn][2],fa[maxn],rev[maxn],sz[maxn],fth[maxn];
int tr[maxn][2];

IL bool Son(int x){ return rs(fa[x]) == x; }
IL bool Isroot(int x){return (ls(fa[x])!=x && rs(fa[x])!=x) ; }
IL void PushUp(int x){ sz[x] = 1+sz[ls(x)]+sz[rs(x)]; }
IL void PushDown(int x){
    if(!rev[x])return; rev[x] = 0;
    rev[ls(x)]^=1; rev[rs(x)]^=1;  swap(ls(x) , rs(x));
}

IL void Rot(RG int x){
    RG int y = fa[x],z = fa[y],c = Son(x);
    if(!Isroot(y))ch[z][Son(y)] = x; fa[x] = z;
    ch[y][c] = ch[x][!c]; fa[ch[y][c]] = y;
    ch[x][!c] = y; fa[y] = x; PushUp(y);
}
IL void Splay(RG int x){
    RG int top = 0; Stk[++top] = x;
    for(RG int i = x; !Isroot(i); i = fa[i])Stk[++top] = fa[i];
    while(top)PushDown(Stk[top--]);
    for(RG int y = fa[x]; !Isroot(x); Rot(x),y = fa[x])
        if(!Isroot(y))Son(x) ^ Son(y) ? Rot(x) : Rot(y);
    PushUp(x);

}

IL void Access(int x){
    for(RG int y = 0; x; y = x,x = fa[x])
         Splay(x),ch[x][1] = y,PushUp(x);
}
IL void Makeroot(int x){Access(x);Splay(x); rev[x]^=1; }
IL void Split(int x,int y){ Makeroot(x); Access(y); Splay(y); }
IL void Link(int x,int y){ if(!x||!y)return; Makeroot(x); fa[x] = y; }
IL void Cut(int x,int y){
    if(!x||!y)return;
    Split(x,y); rs(y) = fa[x] = 0;
    PushUp(x); PushUp(y);
}
IL int Query(RG int x){Makeroot(root); Access(x); Splay(x); return sz[x];}  

set<int>S; set<int>::iterator bf,aft,it;
map<int,int>mp;
IL void NewNode(){cnt++; fa[cnt] = 0; sz[cnt] = 1;}

IL int Insert(){
    RG int data = gi(); S.insert(data);
    RG int dep,cs,dep1=0,dep2=0,v1,v2;
    bf = S.find(data); aft = bf; aft++;
    NewNode(); mp[data] = cnt;
    if(!root){root = cnt; return 1;}
    if(aft != S.end()){ v1 = mp[*aft]; dep1 = Query(v1); }
    if(bf !=S.begin()){bf--; v2 = mp[*bf]; dep2 = Query(v2);}
    cs = (dep1>dep2) ? v1:v2; dep = max(dep1,dep2);
    if(cs==v1)tr[cs][0] = cnt,fth[cnt] = cs;
    if(cs==v2)tr[cs][1] = cnt,fth[cnt] = cs;
    Link(cs,cnt);  return dep+1;
}

IL int Findmin1(){
    it = S.begin(); RG int p = mp[*it],dep;
    dep = Query(p);
    RG int x = p,sn = tr[x][1],ft = fth[x];
    if(x == root)return 1;
    Cut(x,sn); Cut(ft,x); Link(x,root); Link(ft,sn);
    fth[x] = 0; tr[x][1] = root; fth[root] = x; tr[ft][0] = sn; fth[sn] = ft;
    root = x; return dep;
}

IL int Findmax1(){
    it = S.end(); it--; RG int p = mp[*it],dep;
    dep = Query(p);
    RG int x = p,sn = tr[x][0],ft = fth[x];
    if(x == root)return 1;
    Cut(x,sn); Cut(ft,x); Link(x,root); Link(ft,sn);
    fth[x] = 0; tr[x][0] = root; fth[root] = x; tr[ft][1] = sn; fth[sn] = ft;
    root = x; return dep;
}

IL int Findmin2(){
    RG int dep = Findmin1(),rt = root,sn = tr[root][1];
    fth[sn] = 0;  Cut(root,sn);
    root = sn;
    tr[rt][1] = tr[rt][0] = 0;
    it = S.begin(); S.erase(it);
    return dep;
}

IL int Findmax2(){
    RG int dep = Findmax1(),rt = root,sn = tr[root][0];
    fth[sn] = 0;  Cut(root,sn);
    root = sn;
    tr[rt][1] = tr[rt][0] = 0;
    it = S.end(); it--; S.erase(it);
    return dep;
}

IL void Work(){
    RG int c = gi();
    if(c == 1)printf("%d\n",Insert());
    else if(c == 2)printf("%d\n",Findmin1());
    else if(c == 3)printf("%d\n",Findmax1());
    else if(c == 4)printf("%d\n",Findmin2());
    else if(c == 5)printf("%d\n",Findmax2());
}

int main()
{
    freopen("testdate.in","r",stdin);
    M = gi();
    root = 0; while(M--)Work();
    return 0;
}

HNOI2017 单旋的更多相关文章

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

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

  2. 【LG3721】[HNOI2017]单旋

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

  3. 4825: [Hnoi2017]单旋

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

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

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

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

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

  6. bzoj4825 [Hnoi2017]单旋

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

  7. BZOJ:4825: [Hnoi2017]单旋

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

  8. HNOI2017单旋

    单旋 这道题做法贼多,LCT,splay,线段树什么的貌似都行. 像我这种渣渣只会线段树了(高级数据结构学了也不会用). 首先离线所有操作,因为不会有两个点值重复,所以直接离散. 一颗线段树来维护所有 ...

  9. P3721 [AH2017/HNOI2017]单旋

    题目:https://www.luogu.org/problemnew/show/P3721 手玩一下即可AC此题. 结论:插入x后,x要么会成为x的前驱的右儿子,要么成为x的后继的左儿子,这取决于它 ...

随机推荐

  1. 关于webconsole报../website/console.go:35: undefined: ssh.InsecureIgnoreHostkey 错误解决方案

    1.首先,进入webconsole目录删除/opt/webconsole/src/golang.org/x/目录下 crypto文件夹 2.然后,在/opt/webconsole/src/golang ...

  2. elasticsearch节点(角色)类型解释node.master和node.data

    在生产环境下,如果不修改elasticsearch节点的角色信息,在高数据量,高并发的场景下集群容易出现脑裂等问题. 默认情况下,elasticsearch集群中每个节点都有成为主节点的资格,也都存储 ...

  3. cocos2d-x中处理touch事件

    在cocos2d-x中, touch事件分为两种:一种是单点事件, 另一种是多点事件. 单点事件对应的代理方法是: virtual bool ccTouchBegan(CCTouch *pTouch, ...

  4. Halcon一日一练:图像拼接技术2:步骤与例程

    上一篇主要介绍了图像拼接的一些原理和方法,这一篇将主要介绍步骤和例程: 接上一篇: 基于特征的接拼方法,分为四个步骤 1.特征检测:从图像中检测出显著且独特的图像特征,诸如:闭合区域,直线段,边缘,轮 ...

  5. C++ 值类型和引用类型传递示例

    // win32test.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" void swap_point(int * &a , in ...

  6. CSS布局(五) 网页布局方式

    网页实质是块与块之间的位置,块挨着块,块嵌套块,块叠着块. 三种关系:相邻,嵌套,重叠. 下面介绍网页布局的常用几种方式 1.一列布局: 一般都是固定的宽高,设置margin : 0 auto来水平居 ...

  7. tensorflow_mnist数据集一直加载错误的解决办法

    tensorflow数据集一直加载错误的解决办法: from tensorflow.examples.tutorials.mnist import input_data mnist = input_d ...

  8. 《清华梦的粉碎》by王垠

     清华梦的诞生 小时候,妈妈给我一个梦.她指着一个大哥哥的照片对我说,这是爸爸的学生,他考上了清华大学,他是我们中学的骄傲.长大后,你也要进入清华大学读书,为我们家争光.我不知道清华是什么样子,但是我 ...

  9. uva10003 区间DP

    很清晰的区间dp问题.d(i,j)表示断点i到断点j的最小费用,由于开头和结尾也是断点,所以应该加入断点数组,即 cut[0]=0; cut[n+1]=len; 边界就是d(i,i+1)=0; 转移方 ...

  10. UVA-11882 bfs + dfs + 剪枝

    假设当前已经到达(x,y),用bfs判断一下还可以到达的点有maxd个,如果maxd加上当前已经经过的长度小于当前答案的长度就退出,如果相同,就将bfs搜索到的点从大到小排序,如果连最大序列都无法大于 ...