https://www.luogu.org/problemnew/show/P3369
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int sum=0,x=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
x=0;
ch=getchar();
}
while(ch>='0'&&ch<='9')
sum=(sum<<1)+(sum<<3)+(ch^48),ch=getchar();
return x?sum:-sum;
}
inline void write(int x){
if(x<0)
putchar('-'),x=-x;
if(x>9)
write(x/10);
putchar(x%10+'0');
}
const int M=2e5+5;
const int inf=0x3f3f3f3f;
int ch[M][2],val[M],cnt[M],fa[M],sz[M],ncnt,root;
int ck(int x){
return ch[fa[x]][1]==x;
}
void up(int x){
sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+cnt[x];
}
void rotate(int x){
int y=fa[x];
int z=fa[y];
int k=ck(x);
int w=ch[x][k^1];
ch[y][k]=w,fa[w]=y;
ch[z][ck(y)]=x,fa[x]=z;
ch[x][k^1]=y,fa[y]=x;
up(y),up(x);
}
void splay(int x,int goal=0){//将x旋转为goal的儿子,如果goal是0则旋转到根
while(fa[x]!=goal){//一直旋转到x成为goal的儿子
int y=fa[x],z=fa[y];//父节点祖父节点
if(z!=goal)//如果Y不是根节点,则分为两类来旋转(如果随意旋转会达不到查询效果)
ck(x)^ck(y)?rotate(x):rotate(y);
rotate(x);//无论怎么样最后的一个操作都是旋转x
}
if(!goal)
root=x;//如果goal是0,则将根节点更新为x
}
void find(int x){//查找x的位置,并将其旋转到根节点
if(!root)//树空
return ;
int cur=root;
while(ch[cur][x>val[cur]]&&x!=val[cur])//当存在儿子并且当前位置的值不等于x
cur=ch[cur][x>val[cur]];//跳转到儿子,查找x的父节点
splay(cur);//把当前位置旋转到根节点
}
void insertt(int x){//插入x
int cur=root,p=0;//当前位置cur,cur的父节点p
while(cur&&val[cur]!=x){//当u存在并且没有移动到当前的值
p=cur;//向下u的儿子,父节点变为u
cur=ch[cur][x>val[cur]];//大于当前位置则向右找,否则向左找
}
if(cur)//存在这个值的位置
cnt[cur]++;//增加一个数
else{//不存在这个数字,要新建一个节点来存放
cur=++ncnt;//新节点的位置
if(p)//如果父节点非根
ch[p][x>val[p]]=cur;//不存在儿子
fa[cur]=p;//父节点
ch[cur][0]=ch[cur][1]=0;
val[cur]=x;//值
cnt[cur]=sz[cur]=1;//数量,大小
}
splay(cur);//把当前位置移到根,保证结构的平衡。注意前面因为更改了子树大小,所以这里必须Splay上去进行pushup保证size的正确。
}
int kth(int k){
int u=root;
while(true){
if(ch[u][0]&&k<=sz[ch[u][0]])
u=ch[u][0];
else if(k>sz[ch[u][0]]+cnt[u])
k-=sz[ch[u][0]]+cnt[u],u=ch[u][1];
else
return u;
}
}
int pre(int x){//查找x的前驱(0)或者后继(1)
find(x);
if(val[root]<x)//如果当前节点的值小于x并且要查找的是前驱
return root;
int u=ch[root][0];//前驱再左儿子上找
while(ch[u][1])
u=ch[u][1];
return u;//返回位置
}
int succ(int x){
find(x);
if(val[root]>x)//如果当前节点的值大于x并且要查找的是后继
return root;
int u=ch[root][1];//后继在右儿子上找
while(ch[u][0])
u=ch[u][0];
return u;
}
void remove(int x){
int las=pre(x),nex=succ(x);
splay(las,0),splay(nex,las);
//将前驱旋转到根节点,后继旋转到根节点下面
//很明显,此时后继是前驱的右儿子,x是后继的左儿子,并且x是叶子节点
int del=ch[nex][0];//后继的左儿子
if(cnt[del]>1)//如果超过一个
cnt[del]--,splay(del,0);//直接减少一个
else
ch[nex][0]=0;//这个节点直接丢掉(不存在了)
}
void init(){
memset(ch,0,sizeof(cnt));
memset(cnt,0,sizeof(cnt));
memset(sz,0,sizeof(sz));
memset(val,0,sizeof(val));
memset(fa,0,sizeof(fa));
ncnt=root=0;
}
int main(){
int n;
while(~scanf("%d",&n)){
init();
insertt(inf);
insertt(-inf);
while(n--){
int op=read(),x=read();
if(op==1)
insertt(x);
else if(op==2)
remove(x);
else if(op==3)
find(x),write(sz[ch[root][0]]),putchar('\n');
else if(op==4)
write(val[kth(x+1)]),putchar('\n');
else if(op==5)
write(val[pre(x)]),putchar('\n');
else
write(val[succ(x)]),putchar('\n');
}
putchar('\n');
}
return 0;
}
Buy Tickets
http://poj.org/problem?id=2828
题意:给定拆入的位置和值,然后将其序列输出;
考虑用splay树去维护
对于splay树中的一个节点来说左子树上的每一个节点的值一定比该节点小,所以我们把这层关系对应于位置的先后次序:对于一个节点来说,他的左子树的每一个节点一定在这个节点在序列位置的左边,即一定比他先输出,右子树则类似。
然后最终答案即该splay树的中序遍历
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int M=2e5+5; int ch[M][2],sz[M],cnt[M],fa[M],ncnt,root; int val[M]; int ck(int x){ return ch[fa[x]][1]==x; } void up(int x){ sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+cnt[x]; } void rotate(int x){ int y=fa[x]; int z=fa[y]; int k=ck(x); int w=ch[x][k^1]; ch[z][ck(y)]=x,fa[x]=z; ch[y][k]=w,fa[w]=y; ch[x][k^1]=y,fa[y]=x; up(x),up(y); } void splay(int x,int goal=0){ while(fa[x]!=goal){ int y=fa[x],z=fa[y]; if(z!=goal) ck(x)^ck(y)?rotate(x):rotate(y); rotate(x); } if(!goal) root=x; } int kth(int k){ int u=root; while(true){ if(ch[u][0]&&k<=sz[ch[u][0]]) u=ch[u][0]; else if(k>sz[ch[u][0]]+cnt[u]) k-=sz[ch[u][0]]+cnt[u],u=ch[u][1]; else return u; } } void newnode(int &cur,int f,int a){ cur=++ncnt; fa[cur]=f; sz[cur]=cnt[cur]=1; val[cur]=a; ch[cur][0]=ch[cur][1]=0; } void insert(int x,int y){ int p=0; if(!root){ newnode(root,0,y); return; } if(!x){//如果要插入的节点要为head,就将之前的整棵树spaly为该节点的左子树 p=root; sz[p]++; while(ch[p][0]) p=ch[p][0],sz[p]++; newnode(ch[p][0],p,y); splay(ch[p][0]); return ; } int u=kth(x); splay(u); newnode(root,0,y); ch[root][1]=ch[u][1]; fa[ch[u][1]]=root; ch[u][1]=0; ch[root][0]=u; fa[u]=root; up(u),up(root); } void output(int x){ if(ch[x][0]) output(ch[x][0]); printf("%d ",val[x]); if(ch[x][1]) output(ch[x][1]); } int main(){ int n; while(~scanf("%d",&n)){ ncnt=root=0; while(n--){ int id,x; scanf("%d%d",&id,&x); insert(id,x); } output(root); putchar('\n'); } return 0; }
https://www.lydsy.com/JudgeOnline/problem.php?id=1588
前驱:小于当前值的最大值
后继:大于当前值的最小值
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<bits/stdc++.h> using namespace std; const int M=4e4+4; const int inf=0x3f3f3f3; int val[M],fa[M],ch[M][2],cnt[M],ncnt,root; int ck(int x){ return ch[fa[x]][1]==x; } void rotate(int x){ int y=fa[x],z=fa[y],k=ck(x); int w=ch[x][k^1]; ch[y][k]=w,fa[w]=y; ch[z][ck(y)]=x,fa[x]=z; ch[x][k^1]=y,fa[y]=x; } int splay(int x,int goal=0){ while(fa[x]!=goal){ int y=fa[x],z=fa[y]; if(z!=goal) ck(x)^ck(y)?rotate(x):rotate(y); rotate(x); } if(!goal) root=x; } int insertt(int x){ int cur=root,p=0; while(cur&&x!=val[cur]){ p=cur; cur=ch[cur][x>val[cur]]; } if(cur){ cnt[cur]++; splay(cur); return 1; } else{ cur=++ncnt; if(p) ch[p][x>val[p]]=cur; ch[cur][0]=ch[cur][1]=0; cnt[cur]=1; val[cur]=x; fa[cur]=p; } splay(cur); return 0; } void find(int x){ if(!root) return ; int cur=root; while(ch[cur][x>val[cur]]&&x!=val[cur]){ cur=ch[cur][x>val[cur]]; } splay(cur); } int pre(int x){ find(x); if(val[root]<x) return root; int cur=ch[root][0]; while(ch[cur][1]) cur=ch[cur][1]; return cur; } int succ(int x){ find(x); if(val[root]>x) return root; int cur=ch[root][1]; while(ch[cur][0]) cur=ch[cur][0]; return cur; } int main(){ int n,ans=0; scanf("%d",&n); insertt(inf); insertt(-inf); for(int i=1;i<=n;i++){ int x; scanf("%d",&x); if(i==1){ ans+=x; insertt(x); continue; } int sign=insertt(x); if(sign==1) continue; int y=inf; int p=val[pre(x)],q=val[succ(x)]; if(p!=-inf) y=min(y,x-p); if(q!=inf) y=min(y,q-x); ans+=y; } printf("%d",ans); return 0; }
http://poj.org/problem?id=2828
按排名插入值的写法
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int M=2e5+5; int ch[M][2],fa[M],sz[M],cnt[M],val[M],root,ncnt; int ck(int x){ return ch[fa[x]][1]==x; } void push_up(int x){ sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+cnt[x]; } void Rotate(int x){ int y=fa[x],z=fa[y],k=ck(x); int w=ch[x][k^1]; ch[y][k]=w,fa[w]=y; ch[z][ck(y)]=x,fa[x]=z; ch[x][k^1]=y,fa[y]=x; push_up(x);push_up(y); } void splay(int x,int goal=0){ while(fa[x]!=goal){ int y=fa[x],z=fa[y]; if(z!=goal) ck(x)^ck(y)?Rotate(x):Rotate(y); Rotate(x); } if(!goal) root=x; } void newnode(int &cur,int f,int y){ cur=++ncnt; fa[cur]=f; ch[cur][0]=ch[cur][1]=0; sz[cur]=cnt[cur]=1; val[cur]=y; } int Kth(int k){ int cur=root; while(true){ if(ch[cur][0]&&k<=sz[ch[cur][0]]) cur=ch[cur][0]; else if(k>sz[ch[cur][0]]+cnt[cur]) k-=sz[ch[cur][0]]+cnt[cur],cur=ch[cur][1]; else return cur; } } void insertt(int x,int y){ if(!root){///当树为空时 newnode(root,0,y); return ; } if(!x){///当要插入排名为首个时 int p=root; sz[p]++; while(ch[p][0]) p=ch[p][0],sz[p]++; newnode(ch[p][0],p,y); splay(ch[p][0]); return ; } int u=Kth(x); splay(u); newnode(root,0,y); /* ch[root][0]=u,fa[u]=root; ch[u][1]=0; ch[root][1]=ch[u][1]; fa[ch[root][1]]=root; */ ch[root][1] = ch[u][1]; fa[ch[root][1]] = root; ch[u][1] = 0; ch[root][0] = u; fa[u] = root; push_up(u),push_up(root); return ; } void print(int cur){ if(ch[cur][0]) print(ch[cur][0]); printf("%d ",val[cur]); if(ch[cur][1]) print(ch[cur][1]); } int main(){ int n; while(~scanf("%d",&n)){ root=ncnt=0; for(int i=1;i<=n;i++){ int x,y; scanf("%d%d",&x,&y);///x是要插入的排名,y是对应的值 insertt(x,y); } print(root); printf("\n"); } return 0; }