归并树 O(logn*logn*logn) for each query,很慢的说,划分树版http://blog.youkuaiyun.com/leolin_/article/details/6696801
/*
//1,建立归并树后我们得到了序列key[]的非降序排列,由于此时key[]内元素的rank是非递
减的,因此key[]中属于指定区间[s,t]内的元素的rank也是非递减的,所以我们可以用二分法
枚举key[]中的元素并求得它在[s,t]中的rank值,直到该rank值和询问中的rank值相等;
//2,那对于key[]中的某个元素val,如何求得它在指定区间[s,t]中的rank?这就要利用到刚
建好的归并树:我们可以利用类似线段树的query[s,t]操作找到所有属于[s,t]的子区间,然后
累加val分别在这些子区间内的rank,得到的就是val在区间[s,t]中的rank,注意到这和合
并排序的合并过程一致;
//3,由于属于子区间的元素的排序结果已经记录下来,所以val在子区间内的rank可以通过
二分法得到。
//上面三步经过了三次二分操作(query也是种二分),于是每次询问的复杂度是O(log n *
log n * log n)
*/
#define N 100005
#define LogN 18
int seq[LogN][N];
int a[N];
struct node{
int l,r;
}t[N*3];
void build(int id,int l,int r,int dep){
t[id].l = l;
t[id].r = r;
if(l == r){
seq[dep][l] = a[l];
return ;
}
int mid = (l+r)>>1;
build(id<<1,l,mid,dep+1);
build(id<<1|1,mid+1,r,dep+1);
/*Merge Sort*/
int i,j,cnt;
i = l,j = mid+1,cnt = l;
while(i<=mid && j<=r){
if(seq[dep+1][i] < seq[dep+1][j]){
seq[dep][cnt++] = seq[dep+1][i++];
} else {
seq[dep][cnt++] = seq[dep+1][j++];
}
}
if(i == mid+1){
while(j<=r){
seq[dep][cnt++] = seq[dep+1][j++];
}
} else {
while(i<=mid){
seq[dep][cnt++] = seq[dep+1][i++];
}
}
}
int query(int id,int l,int r,int val,int dep){
if(l<=t[id].l && t[id].r<=r){
return lower_bound(&seq[dep][t[id].l], &seq[dep][t[id].r] + 1, val) - &seq[dep][t[id].l];//*
}
int mid = (t[id].l+t[id].r)>>1;
int res = 0;
if(l<=mid){
res += query(id<<1,l,r,val,dep+1);
}
if(r>mid){
res += query(id<<1|1,l,r,val,dep+1);
}
return res;
}
int main(){
int n,m;
while(scanf("%d%d",&n,&m) != -1){
int i,j;
for(i=1;i<=n;i++)scanf("%d",&a[i]);
build(1,1,n,1);
while(m--){
int s,t,k;
scanf("%d%d%d",&s,&t,&k);
k--;//*求第k大的话只要把这行改为k = t-s+1-k即可
int l = 1,r = n,mid;
while(l<r){
mid = (l+r+1)>>1;//*
int pos = query(1,s,t,seq[1][mid],1);
if(pos<=k){
l = mid;
} else r = mid-1;
}
printf("%d\n",seq[1][l]);
}
}
return 0;
}
http://codeforces.com/contest/85/problem/D——线段树,有空过了它