伸展樹
多值版
#include<bits/stdc++.h>
using namespace std;
template<class T> inline bool read(T &x){
x=0;register char c=getchar();register bool f=0;
while(!isdigit(c)){if(c==EOF)return false;f^=c=='-',c=getchar();}
while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(f)x=-x;
return true;
}
template<class T>inline void print(T x){
if(x<0)putchar('-'),x=-x;
if(x>9)print(x/10);
putchar('0'+x%10);
}
typedef long long ll;
const ll MAXN=1e5+8,inf=0x3f3f3f3f,mod=1e9+7;
struct Node {
int val,num,son_num;
int fa,lson,rson;
Node() {val=num=son_num=fa=rson=lson=0;}
Node(int f,int ls,int rs,int v,int n,int sn):
fa(f),lson(ls),rson(rs),val(v),num(n),son_num(sn) {}
}tree[MAXN];
int root,cnt;
inline void init(){root=cnt=0;}
inline bool islson(int x){return tree[tree[x].fa].lson==x?1:0;}
inline void update(int x){
if(!x)return;
tree[x].son_num=tree[x].num;
if(tree[x].lson)tree[x].son_num+=tree[tree[x].lson].son_num;
if(tree[x].rson)tree[x].son_num+=tree[tree[x].rson].son_num;
}
inline void rotate(int x){//默認x有父節點
int f=tree[x].fa,ff=tree[f].fa;//ff可能是0
if(islson(x)){//zig 右旋
tree[f].lson=tree[x].rson,tree[tree[x].rson].fa=f;
tree[x].rson=f,tree[f].fa=x;
}else{//zag 左旋
tree[f].rson=tree[x].lson,tree[tree[x].lson].fa=f;
tree[x].lson=f,tree[f].fa=x;
}
tree[x].fa=ff;
//必須這樣判斷,不能用islson,因爲f的父節點已經是x了
if(tree[ff].lson==f)tree[ff].lson=x;
else tree[ff].rson=x;
update(f);//只需更新深度更大的f,x之後更新
}
inline void splay(int x,int end_pos) {
int f=tree[x].fa;
while(f^end_pos) {
if(tree[f].fa^end_pos) {//如果f不是根
if(islson(x)^islson(f))rotate(x);//zig+zag or zag+zig
else rotate(f);//zig+zig or zag+zag
}rotate(x);
f=tree[x].fa;
}
update(x);//最上層節點還沒更新
root=x;
}
void insert(int v){
if(!root){//如果有節點。
tree[++cnt]=Node(0,0,0,v,1,1);
root=cnt;
return;
}
int now=root,f=0;
while(1){
if(tree[now].val==v){//原來有val節點
tree[now].num++;
tree[now].son_num++;
splay(now,0);
break;
}
f=now;
if(v<tree[now].val)now=tree[now].lson;
else now=tree[now].rson;
if(now==0){//創建節點
tree[++cnt]=Node(f,0,0,v,1,1);//父節點是f
if(v>tree[f].val)tree[f].rson=cnt;
else tree[f].lson=cnt;
splay(cnt,0);
break;
}
}
}
inline int pre(){//返回根節點的val值的前繼的節點編號
int now=tree[root].lson;
while(tree[now].rson)now=tree[now].rson;
return now;
}
inline int nxt(){//後繼
int now=tree[root].rson;
while(tree[now].lson)now=tree[now].lson;
return now;
}
int find_val_rank(int val){//返回值爲val的最小的排名
int now=root,ans=0;
while(1){
//如果當前節點值大於val,進入左子樹
if(val<tree[now].val)now=tree[now].lson;
else{//否則,進入右子樹
//加上值絕對小於val的數量
if(tree[now].lson)ans+=tree[tree[now].lson].son_num;
if(tree[now].val==val){
splay(now,0);
return ans+1;
}
//否則,當前節點值小於val,加上
ans+=tree[now].num;
now=tree[now].rson;
}
}
}
/*
將要刪除的節點旋轉到root
考慮刪除root
1. 如果root有多餘1次出現,直接num--
2. 如果左右子樹都爲空,變成空樹
3. 只有一個兒子
4. 有兩個兒子
*/
inline void del(int val){/
find_val_rank(val);
if(tree[root].num>1){//如果大於一個,直接減少一個。
tree[root].num--;
tree[root].son_num--;
return;
}
if(!tree[root].lson&&!tree[root].rson){//如果左右子樹都爲空,則樹爲空
root=cnt=0;
return;
}
if(!tree[root].lson){//如果沒有左兒子,直接將右兒子作爲根
root=tree[root].rson;
tree[root].fa=0;
return;
}
if(!tree[root].rson){//如果沒有右兒子,將左兒子作爲根
root=tree[root].lson;
tree[root].fa=0;
return;
}
//左右兒子都存在,尋找前繼,把它設爲根
//這樣的話,原來的根就沒有左子樹了
//未開始操作前,新的root的右兒子就是原來的根
int old_root=root,pre_node=pre();
splay(pre_node,0);
tree[root].rson=tree[old_root].rson;
tree[tree[old_root].rson].fa=root;
update(root);
}
//返回第kth名的值
int find_kth_rank(int kth){
int now=root;
while(1){
//如果now有左兒子且左兒子裏節點數大於kth,答案肯定在左兒子
if(tree[now].lson&&kth<=tree[tree[now].lson].son_num)
now=tree[now].lson;
else{//在右兒子或now
int ls=tree[now].lson,sum=tree[now].num;
if(ls)sum+=tree[ls].son_num;//有左兒子,sum加上左兒子裏的數量
if(kth<=sum)return tree[now].val;
//只有左兒子kth>sum,加上now就符合,所以正確。
kth-=sum;//減去左兒子和now節點的的數量,進入右兒子
now=tree[now].rson;
}
}
}
int main() {
int n,op,x;
read(n);
while(n--){
read(op),read(x);
if(op==1)insert(x);
else if(op==2)del(x);
else if(op==3)printf("%d\n",find_val_rank(x));
else if(op==4)printf("%d\n",find_kth_rank(x));
else if(op==5){
insert(x);//查詢的時候先添加,這樣就必定有x節點,就能求出x的前繼了
printf("%d\n",tree[pre()].val);
del(x);
}else{
insert(x);
printf("%d\n",tree[nxt()].val);
del(x);
}
}
return 0;
}
單值版
struct Splay{
int val[MAXN],num[MAXN],ls[MAXN],rs[MAXN],fa[MAXN];
inline void up(int x){//因爲所有節點代表一個值,所以最初是1
num[x]=1;
if(ls[x])num[x]+=num[ls[x]];
if(rs[x])num[x]+=num[rs[x]];
}
int cnt,root;
inline int build(int l,int r,int f){
//建樹,[l,mid-1],mid,[mid+1,r],保證中序遍歷是原序列
int mid=(l+r)>>1;
int id=++cnt;//用另一個變量存儲cnt,遞歸先改變cnt,再return
num[id]=1,fa[id]=f;
scanf("%d",val+id);
if(l==r){ls[id]=rs[cnt]=0;return id;}
if(l<mid)ls[id]=build(l,mid-1,id);
if(r>mid)rs[id]=build(mid+1,r,id);
return up(id),id;
}
inline bool islson(int x){return ls[fa[x]]==x?1:0;}
inline void rotate(int x){//單旋
int f=fa[x],ff=fa[f];
if(islson(x)){//zig
ls[f]=rs[x],fa[rs[x]]=f;
rs[x]=f,fa[f]=x;
}else{//zag
rs[f]=ls[x],fa[ls[x]]=f;
ls[x]=f,fa[f]=x;
}
fa[x]=ff;
if(ls[ff]==f)ls[ff]=x;
else rs[ff]=x;
up(f);//只要更新x下方節點
}
void splay(int x,int pos){//伸展爲pos的子節點
int f=fa[x],ff=fa[f];
while(f^pos){
if(ff^pos){//如果ff就是pos,只需要再旋轉一次即可。
if(islson(x)^islson(f))rotate(x);
else rotate(f);
}
rotate(x),f=fa[x],ff=fa[f];
}up(x);
if(!pos)root=x;//pos可能不爲零
}
void insert(int vv){
cnt++;
if(!root){
val[cnt]=vv,num[cnt]=1,root=cnt;
return;
}
int x=root,f;
while(x){
f=x;
if(vv<val[x])x=ls[x];
else x=rs[x];
}
fa[cnt]=f,val[cnt]=vv,num[cnt]=1;
if(vv>val[f])rs[f]=cnt;
else ls[f]=cnt;
splay(cnt,0);
}
inline int find_kth(int k){//返回第k個節點編號
int x=root;
while(1){
if(ls[x]&&k<=num[ls[x]])x=ls[x];
else{
int sum=1;//每個節點都是唯一值,不會重複出現。
if(ls[x])sum+=num[ls[x]];
if(k<=sum)return splay(x,0),x;
//一定要splay,不然單調數據卡爆
k-=sum;
x=rs[x];
}
}
}
}
伸展樹(區間旋轉)
交換節點下面的所有左右兒子,則中序遍歷結果和原序列相反,即旋轉。
思路:要旋轉的區間爲[l,r],將l-1代表的點旋轉到root,再將r+1代表的點旋轉到root的右兒子處,則:
x代表的是區間內的點 <=> x在r+1代表的點的左子樹裏面
//a序列m次翻轉
#include<bits/stdc++.h>
using namespace std;
template<class T> inline bool read(T &x){
x=0;register char c=getchar();register bool f=0;
while(!isdigit(c)){if(c==EOF)return false;f^=c=='-',c=getchar();}
while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(f)x=-x;
return true;
}
template<class T>inline void print(T x){
if(x<0)putchar('-'),x=-x;
if(x>9)print(x/10);
putchar('0'+x%10);
}
typedef long long ll;
const ll MAXN=1e5+8,inf=0x3f3f3f3f,mod=1e9+7;
int v[MAXN],num[MAXN],ls[MAXN],rs[MAXN],fa[MAXN];
int a[MAXN],n,m,cnt,root;
bool flag[MAXN];
inline void up(int x){//因爲所有節點代表一個值,所以最初是1
num[x]=1;
if(ls[x])num[x]+=num[ls[x]];
if(rs[x])num[x]+=num[rs[x]];
}
inline void down(int x){//下放標記
swap(ls[x],rs[x]);
flag[ls[x]]^=1;
flag[rs[x]]^=1;
flag[x]=0;
}
inline bool islson(int x){return ls[fa[x]]==x?1:0;}
inline int build(int l,int r,int f){
//建樹,[l,mid-1],mid,[mid+1,r],保證中序遍歷是原序列
int mid=(l+r)>>1;
int id=++cnt;//用另一個變量存儲cnt,因爲遞歸先改變cnt,再return
num[id]=1;
fa[id]=f;
v[id]=a[mid];
if(l==r){ls[id]=rs[cnt]=0;return id;}
if(l<mid)ls[id]=build(l,mid-1,id);
if(r>mid)rs[id]=build(mid+1,r,id);
up(id);
return id;
}
inline void rotate(int x){//單旋
int f=fa[x],ff=fa[f];
if(islson(x)){//zig
ls[f]=rs[x],fa[rs[x]]=f;
rs[x]=f,fa[f]=x;
}else{//zag
rs[f]=ls[x],fa[ls[x]]=f;
ls[x]=f,fa[f]=x;
}
fa[x]=ff;
if(ls[ff]==f)ls[ff]=x;
else rs[ff]=x;
up(f);//值更新x下方節點
}
inline void splay(int x,int end_pos){
int f=fa[x],ff=fa[f];
while(f^end_pos){
if(flag[f])down(f);//因爲要改變f和x的位置,所以要先putdown
if(flag[x])down(x);
if(ff^end_pos){//這裏和其他不同,如果ff就是end_pos,只需要再旋轉一次即可。
if(islson(x)^islson(f))rotate(x);
else rotate(f);
}
rotate(x);
f=fa[x];ff=fa[f];
}
up(x);
if(!end_pos)root=x;//end_pos可能不爲零
}
inline int find_kth(int k){//返回第k個節點編號
int x=root;
while(1){
if(flag[x])down(x);
if(ls[x]&&k<=num[ls[x]])x=ls[x];
else{
int sum=1;//每個節點都是唯一值,不會重複出現。
if(ls[x])sum+=num[ls[x]];
if(k<=sum)return x;
k-=sum;
x=rs[x];
}
}
}
inline void change(int x,int y){
int l=find_kth(x-1),r=find_kth(y+1);
//把第x-1個節點旋轉至root
splay(l,0);
splay(r,root);//第y+1個節點旋轉至root右兒子的左兒子
flag[ls[rs[root]]]^=1;
}
void get_ans(int x){//中序遍歷
if(flag[x])down(x);
if(ls[x])get_ans(ls[x]);
a[++cnt]=v[x];
if(rs[x])get_ans(rs[x]);
}
int main() {
read(n),read(m);
for(int i=1;i<=n+2;++i)a[i]=i-1;
root=build(1,n+2,0);
int x,y;
while(m--){
read(x),read(y);
change(x+1,y+1);
}
cnt=0;//下面重新用到了cnt
get_ans(root);
for(int i=2;i<=n+1;++i)printf("%d ",a[i]);
return 0;
}
POJ-3481
#include<iostream>
using namespace std;
template<class T> inline bool read(T &x){
x=0;register char c=getchar();register bool f=0;
while(!isdigit(c)){if(c==EOF)return false;f^=c=='-',c=getchar();}
while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(f)x=-x;
return true;
}
template<class T>inline void print(T x){
if(x<0)putchar('-'),x=-x;
if(x>9)print(x/10);
putchar('0'+x%10);
}
typedef long long ll;
const ll MAXN=1e6+8,inf=0x3f3f3f3f,mod=1e9+7;
int v[MAXN],num[MAXN],ls[MAXN],rs[MAXN],fa[MAXN],cnt,root;
int id[MAXN];
inline bool islson(int x){return ls[fa[x]]==x?1:0;}
inline void update(int x){
num[x]=1;
if(ls[x])num[x]+=num[ls[x]];
if(rs[x])num[x]+=num[rs[x]];
}
inline void rotate(int x){
int f=fa[x],ff=fa[f];
if(islson(x)){
ls[f]=rs[x],fa[rs[x]]=f;
rs[x]=f,fa[f]=x;
}else{
rs[f]=ls[x],fa[ls[x]]=f;
ls[x]=f,fa[f]=x;
}
fa[x]=ff;
if(ls[ff]==f)ls[ff]=x;
else rs[ff]=x;
update(f);
}
inline void splay(int x,int end_pos){
int f=fa[x];
while(f^end_pos){
if(fa[f]){
if(islson(x)^islson(f))rotate(x);
else rotate(f);
}
rotate(x);
f=fa[x];
}
update(x);
if(!end_pos)root=x;
}
inline void insert(int val,int i){
if(!root){
num[++cnt]=1;v[cnt]=val;id[cnt]=i;
root=cnt;fa[cnt]=0;
return;
}
int x=root;
while(1){
if(val<v[x]){
if(ls[x])x=ls[x];
else{
num[++cnt]=1;v[cnt]=val;id[cnt]=i;
fa[cnt]=x;ls[x]=cnt;
splay(cnt,0);
return;
}
}
else{
if(rs[x])x=rs[x];
else{
num[++cnt]=1;v[cnt]=val;id[cnt]=i;
fa[cnt]=x;rs[x]=cnt;
splay(cnt,0);
return;
}
}
}
}
inline int get_high(){
if(!root)return 0;
int x=root;
while(1){
if(rs[x])x=rs[x];
else return x;
}
}
inline int get_low(){
if(!root)return 0;
int x=root;
while(1){
if(ls[x])x=ls[x];
else return x;
}
}
inline int get_h_del(){
int res_pos=get_high();
splay(res_pos,0);
root=ls[res_pos];
fa[root]=0;
return id[res_pos];
}
inline int get_l_del(){
int res_pos=get_low();
splay(res_pos,0);
root=rs[res_pos];
fa[root]=0;
return id[res_pos];
}
int main() {
int op,k,p,res;
while(read(op)&&op){
if(op==1){
read(k),read(p);
insert(p,k);
}
else if(op==2)printf("%d\n",get_h_del());
else if(op==3)printf("%d\n",get_l_del());
}
return 0;
}