splay基础模板(简单修改和翻转)

初学,看的这篇博客 

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<cmath>
#include<sstream>
/* TDD */
#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define fi first
#define se second
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define sc(n) scanf("%d",&n)
#define SC(n,m) scanf("%d %d",&n,&m)
#define SZ(a) int((a).size())
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define drep(i,a,b)	for(int i=a;i>=b;--i)
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const double PI=acos(-1.0);
const double eps=1e-9;
const int N=2e5+5;
int ch[N][2],val[N],cnt[N],par[N],sz[N],rev[N];
//x节点的左右儿子;x存储的权值;x存储的重复权值的个数;x的父亲节点;x子树下储存的权值数 
//(包括重复);翻转标记 
int root,ncnt;
int n,m; 
il void pushup(int x){	sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+cnt[x];} 
il void pushdown(int x){
	if(rev[x]){
		swap(ch[x][0],ch[x][1]);
		rev[ch[x][0]]^=1;
		rev[ch[x][1]]^=1;
		rev[x]=0;
	}
}
il bool ws(int x){	return ch[par[x]][1]==x;} 
void rotate(int x){
	int f=par[x],ff=par[f],k=ws(x),w=ch[x][k^1];
	ch[f][k]=w,par[w]=f;
	ch[ff][ws(f)]=x,par[x]=ff;
	ch[x][k^1]=f,par[f]=x;
	pushup(f),pushup(x);
}
void splay(int x,int goal=0){
	while(par[x]!=goal){
		int f=par[x],ff=par[f];
		if(ff!=goal){
			if(ws(x)==ws(f)) rotate(f);
			else rotate(x);
		}
		rotate(x);
	}
	if(!goal) root=x;
}
void Find(int x){ //找到x值并将其旋转为根 
	int cur=root;
	while(ch[cur][x>val[cur]] && x!=val[cur]){
		cur=ch[cur][x>val[cur]];
	}
	splay(cur);
}
void Insert(int x){
	int cur=root,p=0;
	while(cur && val[cur]!=x){
		p=cur;
		cur=ch[cur][x>val[cur]];
	}
	if(cur) cnt[cur]++;
	else{
		cur=++ncnt;
		if(p) ch[p][x>val[p]]=cur;
		ch[cur][0]=ch[cur][1]=0;
		par[cur]=p,val[cur]=x;
		cnt[cur]=sz[cur]=1;
	}
	splay(cur);
}
/*查询*/ 
int Kth(int k){ //第k-1大 (因为一开始插入了-inf)
	int cur=root;
	while(1){
		pushdown(cur);//有区间操作时才需pushdown 
		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 Rank(int x){ //x的rank 
	Find(x);
	cout<<sz[ch[root][0]]<<endl;
}
int Pre(int x){ //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 Back(int x){ //x的后继 
	Find(x);
	if(val[root]>x) return root;
	int cur=ch[root][1];
	while(ch[cur][0]) cur=ch[cur][0];
	return cur;
}
void Remove(int x){ //删除x 
	int last=Pre(x),beh=Back(x);
	splay(last),splay(beh,last);
	int del=ch[beh][0];
	if(cnt[del]>1){
		cnt[del]--;
		splay(del);
	}
	else ch[beh][0]=0;
}
void Reverse(int l,int r){ //翻转[l,r]区间 
	int x=Kth(l),y=Kth(r+2);
	splay(x),splay(y,x);
	rev[ch[y][0]]^=1;
}
void Output(int x){ //中序遍历输出 
	pushdown(x);
	if(ch[x][0]) Output(ch[x][0]);
	if(val[x]>=1 && val[x]<=n) printf("%d ",val[x]);
	if(ch[x][1]) Output(ch[x][1]); 
}
void Print(int l,int r){ //输出[l,r]
	int x=Kth(l),y=Kth(r+2);
	splay(x),splay(y,x);
	Output(ch[y][0]);
} 
int main(){
	Insert(inf),Insert(-inf); //先形成树形 
	
	
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值