SDOI2007 超级数组

Description

  一般的数组大家都经常使用,相信很多同学没有见过下面的超级数组。
  超级数组存储的是一些正整数,它还支持下面的两个操作
1.插入一个元素,命令是 "i key" 。 key 是要插入的数。
2.输出第 k 大元素并删除该元素,命令是 "d k"。输出第 k 大元素并删除它。
“第 k 大”是指:现有的数中,如果从小到大排好序,从最小的开始作为第一大算起,一直数到第 k 个。
  现在给出一个开始是空的超级数组,请维护好该数组。

Input

  第一行 n、m(n<=1 000 000 000 , m<=100 000)。表示插入数的范围是 1 至n ,共有m 条命令(包括插入和删除)。
  输入 以下 m 行,每行一条命令,如题中描述。每条命令中字母和后面的数字之间一个空格。
  保证输入数据是正确的,删除的数一定存在。

Output

  对于每个删除命令,按删除命令顺序输出删除的数,每个数一行

Sample Input

100 10

i 57

i 99

i 65

d 3

i 89

d 2

d 2

d 1

i 93

i 29

Sample Output

99

65

89

57

做了普通平衡树之后,这些题感觉都好菜= =

#include<bits/stdc++.h>
using namespace std;
#define Inc(i,L,r) for(register int i=(L);i<=(r);++i)
#define Red(i,r,L) for(register int i=(r);i>=(L);--i)
const int N = 1e5+10;
long long sum;
struct Splay{
	int rt,cur,p[N],ch[N][2];
	int k[N],siz[N],cnt[N];
	#define Ls(v) ch[v][0]
	#define rs(v) ch[v][1]
	#define sum(v) siz[v]=siz[Ls(v)]+siz[rs(v)]+cnt[v]
	inline void rot(int x){
		int f=p[x],gf=p[f],type=ch[f][1]==x,son=ch[x][!type];
		ch[p[son]=f][type]=son,sum(f);
		ch[p[f]=x][!type]=f,sum(x);
		ch[p[x]=gf][ch[gf][1]==f]=x;
	}
	inline void splay(int x){
		while(p[x]){
			if(p[p[x]]&&((ch[p[p[x]]][1]==p[x])==(ch[p[x]][1]==x)))rot(p[x]);
			rot(x);
		}
		rt=x;
	}
	inline void insert(int &x,int fa,int v){
		if(k[x]==v)return ++siz[x],++cnt[x],splay(x),void();
		if(!x)return siz[x=++cur]=cnt[x]=1,p[x]=fa,k[x]=v,splay(x),void();
		insert(ch[x][k[x]<v],x,v);
	}
	inline int FindPre(int x){
		if(!Ls(x))return 0;
		x=Ls(x);
		while(rs(x))x=rs(x);
		return x;
	}
	inline void Delete(int x,int v){
		if(k[x]==v){
			if(cnt[x]>1)return --siz[x],--cnt[x],splay(x),void();
			splay(x);
			if(Ls(x)){
				int tmp=rs(x),New=FindPre(x);
				splay(New);
				rs(p[tmp]=New)=tmp;
			}else p[rs(x)]=0,rt=rs(x);
			return ;
		}
		Delete(ch[x][k[x]<v],v);
	}
	inline int FindKth(int kth){
		int x=rt;
		while(1){
			if(siz[Ls(x)]+1<=kth&&kth<=siz[Ls(x)]+cnt[x])break;
			if(siz[Ls(x)]+cnt[x]<kth)kth-=siz[Ls(x)]+cnt[x],x=rs(x);
			else x=Ls(x);
		}
		return x;
	}
	inline void PrintKth(int kth){
		int p=FindKth(kth);
		cout<<k[p]<<"\n";
		Delete(rt,k[p]);
	}
}sp;
int main(){
	int n,m;scanf("%d%d",&n,&m);
	while(m--){
		char op=getchar();while(op!='i'&&op!='d')op=getchar();
		int k;scanf("%d",&k);
		if(op=='i')sp.insert(sp.rt,0,k);
		if(op=='d')sp.PrintKth(k);
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值