poj 2761 splay tree

这道题 可以用很多方法做像划分树之类滴~~~

用splay虽然比划分树慢了一点,不过也只是慢了一点呀,想想有通用的解法,何必用不太常用的划分树喃~~

#include<stdio.h>   
#include<string.h>   
#include <cmath>
#include<algorithm>   
#define fr(i,s,n) for(int i=s;i<n;++i)
#define _fr(i,n,s) for(int i=n-1;i>=s;--i)
#define fi freopen("in.txt","r",stdin)
#define cl(a) memset(a,0,sizeof(a))
using namespace std;
typedef long long ll;
const int N=1000010;

int nxt[N],data[N];  // 内存池	

int l[N],r[N],siz[N],fa[N]; //siz以i为根的树中的孩子数目
int n,m;

//这里的root 都是指的当前的根
class Spt{
public:
	Spt(){
		fr(i,0,N) nxt[i]=i+1;
	}
	void zig(int &pos); 
	void zag(int &pos);
	void splay(int &pos,int &root);	 
	int join(int &s1,int &s2);        
	void split(int x,int &root,int &s1,int &s2);  
	void remove(int x,int &root);      

	int bst_find(int x,int root);
	int spt_find(int x,int &root);
	int bst_insert(int x,int &root);   
	void spt_insert(int x,int &root);  

	int bst_find_kth(int k,int root);  
	int spt_find_kth(int k,int &root);
	int findmx(int &pos);
	int findmn(int &pos);

	void init();            
	int newnode(int x);    
	void delnode(int pos);  
	void disp(int root);
};

struct interval{
	int l,r,k,pos;
	bool operator < (const interval &x){
		if ( r == x.r) return l<x.l;
		return r<x.r;
	}
}inter[50010];

int num[N];
int ans[50010];
int main(){
	n=10;
	Spt spt;
	int ROOT=0;
	scanf("%d%d",&n,&m);
	
	fr(i,1,n+1){
		scanf("%d",&num[i]);
	}
	fr(i,0,m) {scanf("%d %d %d",&inter[i].l,&inter[i].r,&inter[i].k);inter[i].pos=i;}

	sort(inter,inter+m);
	
	fr(i,inter[0].l,inter[0].r+1){
		spt.spt_insert( num[i] ,ROOT);
	}
	//spt.disp(ROOT);
	ans[inter[0].pos] = spt.spt_find_kth(inter[0].k,ROOT);
	int l=inter[0].l,r=inter[0].r;
	fr(i,1,m){
		if ( inter[i].l > l) {
			fr(ii,l,inter[i].l) spt.remove(num[ii],ROOT);
		}else{
			fr(ii,inter[i].l,l) spt.spt_insert(num[ii] ,ROOT);
			
			//spt.disp(ROOT);
		}
		if (inter[i].r > r){
			fr(ii,r+1,inter[i].r+1){

				spt.bst_insert(num[ii],ROOT);
			  //  spt.disp(ROOT);
			}
		}else{
			fr(ii,inter[i].r+1,r+1) spt.remove(num[ii],ROOT);
		}
		l=inter[i].l;
		r=inter[i].r;
		ans[inter[i].pos] = spt.spt_find_kth(inter[i].k,ROOT);
	}


	fr(i,0,m){
		printf("%d\n",ans[i]);
	}
	return 0;
}
void Spt::zig(int &pos){
	int p = fa[pos];
	l[p] = r[pos];
	if (r[pos]) fa[ r[pos] ]=p;
	r[pos] = p;

	fa[ pos ] = fa[p];
	fa[p] = pos;

	siz[pos] = siz[p];
	siz[p] = siz[ l[p] ] + siz[r[p]] +1;

	if (data[fa[pos]] > data[pos]) l[fa[pos]] = pos;
	else r[ fa[pos] ] = pos;
}
void Spt::zag(int &pos){
	int p = fa[pos];

	r[p] = l[pos];
	if (l[pos]) fa[ l[pos] ] = p;

	l[pos] = p;
	fa[pos] = fa[p];
	fa[p] = pos;

	siz[pos] = siz[p];
	siz[p] = siz[ l[p] ] + siz[r[p]] +1;

	if (data[fa[pos]] > data[pos]) l[fa[pos]] = pos;
	else r[ fa[pos] ] = pos;
}
void Spt::splay( int &pos,int &root ){
	int p;
	while( fa[pos] ){
		p = fa[pos];
		if ( !fa[p] ){
			if (pos == l[p]) zig(pos);
			else if( pos == r[p] ) zag(pos);
		}
		else{
			int g = fa[p];
			if (l[p] == pos && l[g] == p){
				zig(p);zig(pos);
			}
			else if (l[g] == p && r[p] == pos ){
				zag(pos);zig(pos);
			}
			else if (r[g] == p && l[p] == pos){
				zig(pos);zag(pos);
			}
			else if (r[g] == p && r[p] == pos){
				zag(p);zag(pos);
			} 
		}
	}
	root = pos;
}

void Spt::init(){
	fr(i,0,n) nxt[i]=i+1;
}
int Spt::newnode( int x ){
	int p = nxt[0];
	nxt[0] = nxt[p];
	data[p] = x;
	siz[p]=1;
	return p;
}
void Spt::delnode(int pos){
	l[pos] = r[pos] = fa[pos] =0;
	nxt[pos] = nxt[0];
	nxt[0] = pos;
	siz[pos]=0;
}
int Spt::bst_insert( int x,int &root ){  
	if(!root){ root = newnode(x); return root;}
	else if ( x < data[root] ){
		int q = bst_insert( x , l[root]);
		++siz[root];
		fa[ l[root] ]= root;
		return q;
	}else{
		++siz[root];
		int q = bst_insert( x , r[root]);
		fa[ r[root] ]= root;
		return q;
	}
}
void Spt::spt_insert(int x,int &root){
	int q = bst_insert(x,root);
	splay(q,root);
}
int Spt::bst_find(int x,int root){
	if ( !root) return 0;
	if (x == data[root] ) return root;
	else if (x < data[root]) return bst_find(x,l[root]);
	else return bst_find(x,r[root]);
}
int Spt::spt_find(int x,int &root){
	int q = bst_find(x,root);
	if ( q ) splay(q,root);
	return q;
}
int Spt::findmx( int &root ){
	int p = root;
	while ( r[p] ) p = r[p];
	splay(p,root);
	return p;
}

int Spt::join(int &s1,int &s2){
	fa[s1] = fa[s2] = 0;
	if (!s1) return s2;
	if (!s2) return s1;
	int q = findmx(s1);  //findmx以后 是就变成了树根

	siz[s1] += siz[s2];
	r[s1] = s2;
	fa[s2] = s1;
	return s1;  
}

void Spt::split(int x,int &root,int &s1,int &s2){
	int p = spt_find(x,root);
	s1 = l[p];
	s2 = r[p];
}
void Spt::remove(int x ,int &root){
	int q = spt_find(x,root);  //因为是spt_find找到后就已经在顶部了
	if (q) {
		int tmp = root;
		root = join(l[root],r[root]);
		delnode(tmp);
	}
}
void Spt::disp(int root){
	if (!root) return ;
	disp(l[root]);
	printf("%d\n",data[root]);
	disp(r[root]);
}

int Spt::bst_find_kth( int k,int root){  
	if (k <= siz[l[root]])	return bst_find_kth(k,l[root]);
	else {
		k-=siz[l[root]];
		if (k==1){ 
			return root;
		}
		return bst_find_kth(k-1,r[root]);
	}
}
int Spt::spt_find_kth(int k,int &root){
	int p = bst_find_kth(k,root);
	splay(p,root);
	return data[p];
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值