题意:
求区间第K小
思路:
主席树
(此题数据巨水,建议同时通过 POJ 2104 HDU 2665)
代码:
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
#define ls l,mid
#define rs mid+1,r
#define mi (l+r)/2
const int MAXN=1e5+7;
vector <int> a;
typedef struct Node{
int val;
int son[2];
}Node;
Node tree[MAXN*20];
int b[MAXN];
int cnt,pos,rtid[MAXN],ans;
int new_node(){
int rt=++cnt;
tree[rt].val=0;
tree[rt].son[0]=tree[rt].son[1]=0;
return rt;
}
int build(int l,int r){
int rt=new_node();
if(l==r){
return rt;
}
int mid=mi;
tree[rt].son[0]=build(ls);
tree[rt].son[1]=build(rs);
return rt;
}
void update(int l,int r,int rt,int lart){
tree[rt].val=tree[lart].val;
tree[rt].val++;
if(l==r) return ;
int mid=mi;
if(pos>mid){
tree[rt].son[0]=tree[lart].son[0];
tree[rt].son[1]=new_node();
update(mid+1,r,tree[rt].son[1],tree[lart].son[1]);
}else{
tree[rt].son[1]=tree[lart].son[1];
tree[rt].son[0]=new_node();
update(l,mid,tree[rt].son[0],tree[lart].son[0]);
}
}
int query(int l,int r,int rt,int lart,int k){
if(l==r) return l;
int mid=mi;
int sum=tree[tree[rt].son[0]].val-tree[tree[lart].son[0]].val;
if(sum>=k) return query(ls,tree[rt].son[0],tree[lart].son[0],k);
else return query(rs,tree[rt].son[1],tree[lart].son[1],k-sum);
}
void ini(){
a.clear();cnt=0;
}
int main()
{
int n,m,x,st,en,k,T;
while(scanf("%d%d",&n,&m)!=-1){
ini();
for(int i=1;i<=n;i++) scanf("%d",&b[i]),a.push_back(b[i]);
sort(a.begin(),a.end());a.erase(unique(a.begin(),a.end()),a.end());
int len=a.size();
rtid[0]=build(1,len);
for(int i=1;i<=n;i++){
pos=lower_bound(a.begin(),a.end(),b[i])-a.begin()+1;
rtid[i]=++cnt;
update(1,len,rtid[i],rtid[i-1]);
}
for(int i=1;i<=m;i++){
scanf("%d%d%d",&st,&en,&k);
ans=query(1,len,rtid[en],rtid[st-1],k);
printf("%d\n",a[ans-1]);
}
}
}