HDU 2852--KiKi's K-Number 主席树无序第K大+删除结点

For the k-th number, we all should be very familiar with it. Of course,to kiki it is also simple. Now Kiki meets a very similar problem, kiki wants to design a container, the container is to support the three operations. 

Push: Push a given element e to container 

Pop: Pop element of a given e from container 

Query: Given two elements a and k, query the kth larger number which greater than a in container; 

Although Kiki is very intelligent, she can not think of how to do it, can you help her to solve this problem? 

Input

Input some groups of test data ,each test data the first number is an integer m (1 <= m <100000), means that the number of operation to do. The next m lines, each line will be an integer p at the beginning, p which has three values: 
If p is 0, then there will be an integer e (0 <e <100000), means press element e into Container. 

If p is 1, then there will be an integer e (0 <e <100000), indicated that delete the element e from the container   

If p is 2, then there will be two integers a and k (0 <a <100000, 0 <k <10000),means the inquiries, the element is greater than a, and the k-th larger number. 

Output

For each deletion, if you want to delete the element which does not exist, the output "No Elment!". For each query, output the suitable answers in line .if the number does not exist, the output "Not Find!".

Sample Input

5
0 5
1 2
0 6
2 3 2
2 8 1
7
0 2
0 2
0 4
2 1 1
2 1 2
2 1 3
2 1 4

Sample Output

No Elment!
6
Not Find!
2
2
4
Not Find!

 

小细节错误,看了这篇豁然开朗

题意:0操作加数,1操作删一个数,2操作,查询比e大的第K大的数

这题要实时操作,而且数最大1e5,不需要离散化,但不离散化,插入无序,无法像HDU 4417 Super Mario 二分找出e的下标,

需要再写一个query来找(这里命名为rank1函数)

删除结点注意我们还是把他加入到主席树中,但是后面找第K大的时候不能把它加入总数中。

#include<bits/stdc++.h>
using namespace std;
#define lson l,m,ls[rt]
#define rson m+1,r,rs[rt] 
typedef long long ll;
const int maxn = 1e5 + 5;
int ls[maxn*30],rs[maxn*30],tot,rts[maxn];//tot为总结点数 ,rts为每个位置的线段树的根
int t[maxn*30];//重点!权值线段树,存的是每个数出现次数
int a[maxn],num[maxn];//原数组和离散化的
int vis[maxn];
int tmp;

void build(int l,int r,int &rt)
{
	rt = ++tot;
	t[rt] = 0; 
	if(l==r)return ;	
		int m = l+r>>1;
	build(lson); 
    build(rson);
		
  return ;
	
}

void add(int p,int C,int l,int r,int &rt,int lst)//p为数的大小
{
	rt = ++tot;
	ls[rt] = ls[lst],rs[rt] = rs[lst];
	t[rt] = t[lst] +C;	
	if(l==r){
	   // t[rt] = t[lst] + C;	
		//上一个版本的结点拷贝信息,一般C=1,表示多了一个数,也就出现次数+1
		return ;
	}	
		int m = l+r>>1;
	if(p<=m)
	   add(p,C,lson,ls[rt]); 
	else
	   add(p,C,rson,rs[rt]);
	   
	   return ;
	   
	   //t[rt]=t[ls[rt]]+t[rs[rt]];//pushup

}

void rank1(int p,int l,int r,int tt)//第一种写法
{
    if(r==l)
    {
        tmp+=t[tt];
        return;
    }
    int mid=(l+r)/2;
    if(p<=mid) rank1(p,l,mid,ls[tt]);
    else tmp+=t[ls[tt]],rank1(p,mid+1,r,rs[tt]);
    return ;
}

//int rank1(int p,int l,int r,int rt)//第二种写法
//{
//	if(l==r)
//	{
//		return t[rt];
//	}
//	int m=l+r>>1;
//    int ret=0;
//	if(p<=m)
//	   ret+=rank1(p,lson);
//    else
//	    ret=t[ls[rt]]+rank1(p,rson);
//	    
//	    return ret;
//	
//		 
//}
 
 int query(int l,int r,int rt,int k)//区间查询
 {
 	if(l==r)return l;
 	int m=l+r>>1;
    int  nu=t[ls[rt]];     	
	 //int nu=t[ls[rt]-ls[lst]];之前逗比写错
 	if(k<=nu)
 	  return query(lson,k);
 	  else{
 	  	     
 	  		   return query(rson,k-nu);
	   }

 }

int N,M,c,x,y,k,o,q;
int main()
{
	while(~scanf("%d",&M))	
	{
		memset(t,0,sizeof(t));
		memset(vis,0,sizeof(vis));
	 tot=0;
	int cnt=0;//结点数
	int cnt2=0;//实际数量
	int max1=0;
	//build(0,1,rts[0]);
	//int root=rts[0];
		for(int i=0;i<M;i++)
		{
			scanf("%d",&q);
			if(q==0){
				++cnt;
				++cnt2;
				
				scanf("%d",&o);
				max1=max(max1,o);
				vis[o]++;
				add(o,1,1,maxn,rts[cnt],rts[cnt-1]);
			}
			if(q==1){
				scanf("%d",&o);
				if(vis[o])
				{
					cnt++;//便于rts不冲突
					cnt2--;//把-1当做一个结点,但实际是没有这个数
					vis[o]--;
					add(o,-1,1,maxn,rts[cnt],rts[cnt-1]);
				}
				else
				printf("No Elment!\n");
			
			}
			if(q==2){
				scanf("%d%d",&o,&k);
                       tmp=0;
			rank1(o,1,maxn,rts[cnt]);
			   //cout<<z<<endl;
			   if(o<=max1&&k+tmp<=cnt2)
			   printf("%d\n",query(1,maxn,rts[cnt],k+tmp));
			   else
			   printf("Not Find!\n");
			}
		}

		
	}
		
	return 0;
}

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值