https://blog.csdn.net/clove_unique/article/details/50630280
https://baijiahao.baidu.com/s?id=1613228134219334653&wfr=spider&for=pc
Tyvj 1728 普通平衡树
Description
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
1. 插入x数
2. 删除x数(若有多个相同的数,因只删除一个)
3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
4. 查询排名为x的数
5. 求x的前驱(前驱定义为小于x,且最大的数)
6. 求x的后继(后继定义为大于x,且最小的数)
Input
第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)
Output
对于操作3,4,5,6每行输出一个数,表示对应答案
Sample Input
10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598
Sample Output
106465
84185
492737
HINT
1.n的数据范围:n<=100000
2.每个数的数据范围:[-2e9,2e9]
#include<cstdio>
using namespace std;
const int N=100000+15;
int root,sz,ch[N][2],f[N],siz[N],cnt[N],val[N];
inline void clear(int x) {ch[x][0]=ch[x][1]=f[x]=siz[x]=cnt[x]=val[x]=0;}
inline int get(int x) {return ch[f[x]][1]==x;}
inline void pushup(int x)
{if(!x) return;
siz[x]=cnt[x];
if(ch[x][0]) siz[x]+=siz[ch[x][0]];
if(ch[x][1]) siz[x]+=siz[ch[x][1]];
}
inline void rotate(int x)
{int fa=f[x],old=f[fa],wh=get(x);
ch[fa][wh]=ch[x][wh^1]; f[ch[fa][wh]]=fa;
ch[x][wh^1]=fa; f[fa]=x;
f[x]=old;
if(old) ch[old][ch[old][1]==fa]=x;
pushup(fa); pushup(x);
}
inline void splay(int x)
{while(f[x]!=0)
{int y=f[x];int z=f[y];
if(z!=0)
(ch[z][1]==y)^(ch[y][1]==x)?rotate(x):rotate(y);
rotate(x);
}
root=x;
}
void insert(int x){
int y=0,now=root;
while(now&&val[now]!=x)y=now,now=ch[now][x>val[now]];
if(now){cnt[now]++;pushup(now); }
else {
now=++sz; ch[sz][0]=ch[sz][1]=0;
cnt[now]=siz[now]=1;
f[now]=y;val[now]=x;
if(y)ch[y][x>val[y]]=now;
}
pushup(y);splay(now);
}
inline int find(int x)
{int re=0,now=root;
while(1)
{if(x<val[now]) now=ch[now][0];
else {if(ch[now][0]) re+=siz[ch[now][0]];
if(x==val[now]) {splay(now); return re+1;}
re+=cnt[now];
now=ch[now][1];
}
}
}
inline int getkth(int k)
{int now=root;
while(1)
{if(ch[now][0] && k<=siz[ch[now][0]]) now=ch[now][0];
else
{int t=(ch[now][0]?siz[ch[now][0]]:0)+cnt[now];
if(k<=t) return val[now];
k-=t; now=ch[now][1];
}
}
}
inline int pre()
{int now=ch[root][0];
while(ch[now][1]) now=ch[now][1];
return now;
}
inline int nxt()
{int now=ch[root][1];
while(ch[now][0]) now=ch[now][0];
return now;
}
inline void del(int x)
{ find(x);
if(cnt[root]>1){cnt[root]--; pushup(root); return;}
if(!ch[root][0]&&!ch[root][1]) {clear(root); root=0; return;}
if(!ch[root][0])
{int old=root; root=ch[root][1]; f[root]=0; clear(old); return;}
if(!ch[root][1])
{int old=root; root=ch[root][0]; f[root]=0; clear(old); return;}
int old=root; splay(pre());
f[ch[old][1]]=root; ch[root][1]=ch[old][1];
clear(old);
pushup(root);
}
int main()
{
int n,opt,x; scanf("%d",&n);
while(n--)
{scanf("%d%d",&opt,&x);
if(opt==1) insert(x);
else if(opt==2) del(x);
else if(opt==3) printf("%d\n",find(x));
else if(opt==4) printf("%d\n",getkth(x));
else if(opt==5) {insert(x); printf("%d\n",val[pre()]); del(x);
}
else if(opt==6) {insert(x); printf("%d\n",val[nxt()]); del(x);
}
}
return 0;
}
【模板】文艺平衡树(Splay)
题目背景
这是一道经典的Splay模板题——文艺平衡树。
题目描述
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1
输入输出格式
输入格式:
第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2,⋯n−1,n) m表示翻转操作次数
接下来m行每行两个数 [l,r]数据保证 1≤l≤r≤n
输出格式:
输出一行n个数字,表示原始序列经过m次变换后的结果
输入输出样例
输入样例#1:
5 3
1 3
1 3
1 4
输出样例#1:
4 3 2 1 5
说明
n,m≤100000
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=100000+15; const int inf=2147483640;
int n,root,sz,ch[N][2],siz[N],val[N],f[N],rev[N];
inline int get(int x) {return ch[f[x]][1]==x;}
inline void clear(int x){ch[x][0]=ch[x][1]=siz[x]=val[x]=f[x]=rev[x]=0;}
inline void pushup(int x) {if(x)siz[x]=1+siz[ch[x][0]]+siz[ch[x][1]]; }
inline void pass(int x) {rev[x]^=1; swap(ch[x][0],ch[x][1]); }
inline void pushdown(int x)
{if(rev[x])
{rev[x]=0;
if(ch[x][0]) pass(ch[x][0]);
if(ch[x][1]) pass(ch[x][1]);
}
}
inline void rotate(int x)
{int fa=f[x],old=f[fa],wh=get(x);
ch[fa][wh]=ch[x][wh^1]; f[ch[fa][wh]]=fa;
ch[x][wh^1]=fa; f[fa]=x;
f[x]=old;
if(old) ch[old][ch[old][1]==fa]=x;
pushup(fa); pushup(x);
}
inline void splay(int x,int aim)
{
while(f[x]!=aim)
{int y=f[x],z=f[y];
if(z!=aim)
(ch[z][1]==y)^(ch[y][1]==x)?rotate(x):rotate(y);
rotate(x);
}
if(aim==0) root=x;
}
void insert(int x){
int y=0,now=root;
while(now&&val[now]!=x)y=now,now=ch[now][x>val[now]];
if(now){pushup(now); }
else {
now=++sz; ch[sz][0]=ch[sz][1]=0;
siz[now]=1;
f[now]=y;val[now]=x;
if(y)ch[y][x>val[y]]=now;
}
if(y) pushup(y);splay(now,0);
}
inline int getkth(int k)
{int now=root;
while(1)
{pushdown(now);
if(k<=siz[ch[now][0]]) now=ch[now][0];
else if(siz[ch[now][0]]+1==k) return now;
else k=k-siz[ch[now][0]]-1,now=ch[now][1];
}
}
void print(int x)
{pushdown(x);
if(ch[x][0]) print(ch[x][0]);
if(val[x]>1 && val[x]<n+2) printf("%d ",val[x]-1);
if(ch[x][1]) print(ch[x][1]);
}
int main()
{
int m,x,y; scanf("%d%d",&n,&m);
for(int i=1;i<=n+2;++i)insert(i);
while(m--)
{scanf("%d%d",&x,&y);
x=getkth(x),y=getkth(y+2);
splay(x,0); splay(y,x);
pass(ch[ch[root][1]][0]);
}
print(root);
return 0;
}