poj 2104 K-th Number 静态区间第K大 可持续数据结构


静态区间第K大。。

首先应该会 集合第K大的方法。 按值建树,[i,j] 分成【i,p】 【p+1,j】 线段树中的均分。 如果sum(i,p)>=k ,说明第k大在左区间,接下来在左区间找第k大,否则 在右区间找 第k-sum(i,p)大。。

利用可持续数据结构 相减的性质, 每次求出在下标 left 到right ,值在 【i,p】的数的个数。


#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <cstring>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <assert.h>
#include <queue>
#define REP(i,n) for(int i=0;i<n;i++)
#define TR(i,x) for(typeof(x.begin()) i=x.begin();i!=x.end();i++)
#define ALLL(x) x.begin(),x.end()
#define SORT(x) sort(ALLL(x))
#define CLEAR(x) memset(x,0,sizeof(x))
#define FILLL(x,c) memset(x,c,sizeof(x))
using namespace std;
const double eps = 1e-9;
#define LL long long 
#define pb push_back
const int maxn = 100100;
int n ,m ;
map<int ,int >mp;
map<int ,int >::iterator it;
int idx[maxn];
int num[maxn];

struct Node{
     Node *l,*r;
     int sum;
}nodes[maxn *25];
Node *root[maxn];
struct Seg{
	 Node *null;
	 int C;
	 void init(){
	 	 C = 0 ;
	 	 null = &nodes[C++];
	     null->l = null->r = null;
	     null->sum = 0;
	     root[0] = null;
	 }
	 Node * update(int pos,int left ,int right ,Node *root,int val){
	 	  Node *rt = &nodes[C++];
	 	  rt->l = root->l;
	 	  rt->r = root->r;
	 	  rt->sum = root->sum;
	 	  if(left == right){
	 	  	  rt->sum += val;
	 	  	  return rt;
	 	  }
	 	  int mid = (left + right)/2;
	 	  if(pos<= mid){
	 	  	  rt->l = update(pos,left,mid,root->l,val);
	 	  }
	 	  if(pos>mid){
	 	  	  rt->r = update(pos,mid+1,right,root->r,val);
	 	  }
	 	  rt->sum = rt->l->sum + rt->r->sum;
	 	  return rt;
	 }
	 int query(int left ,int right,int k,Node * rroot ,Node * lroot){
	 	     if(left ==right){
	 	     	return left;
	 	     }
	 	     int mid = (left +right )/2;
	 	     int s = rroot->l->sum - lroot->l->sum;
	 	    // cout << s << " "<<k<<"  "<<left << "  "<<right<<endl; 
	 	     if(s>=k){
	 	     	 return query(left,mid,k,rroot->l,lroot->l); 
	 	     }else{
	 	     	 return query(mid+1,right,k-s,rroot->r,lroot->r);
	 	     }
	 }
}T;
int main(){
    while(~scanf("%d%d",&n,&m)){
    	  mp.clear();
    	  for(int i=1;i<=n;i++){
    	       scanf("%d",&num[i]);
    	       mp[num[i]] =1; 
    	  }
    	  int tot = 0;
    	  for(it=mp.begin();it!= mp.end();it++){
    	  	   tot++ ;
    	  	   it->second = tot;
    	  	   idx[tot] = it->first;
    	  }
    	  T.init();
          for(int i =1;i<=n;i++){
               root[i] = T.update(mp[num[i]],1,n,root[i-1],1);	   
          }  	  
          for(int i =1;i<=m;i++){
          	  int a,b,k;
          	  scanf("%d%d%d",&a,&b,&k);
          	  int ans = T.query(1,n,k,root[b],root[a-1]);
          	  printf("%d\n",idx[ans]);
          }
    }      
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值