12
27
2015
0

区间第k大

总算会写主席树了好开桑~

题目描述

老师给大家n个不同的数字a1,a2, ... , an, 问你从小到大第k个的数字这个问题很简单。但现在老师要加大难度,要大家一口气回答m个询问,每个询问给定一个区间[x, y] 问你[x, y]之间从小到大排序后第k个数是多少?

输入

输入n, m

然后一行输入n个不同的整数

然后输入m

每行输入x, y, k,表示询问[x, y]区间里从小到大排序后第k个数是多少

 

输出

对于每个询问输出第k个数字

样例输入

7 3
1 5 2 6 3 7 4
2 5 3
4 4 1
1 7 3

样例输出

5
6
3

对每个前缀建一棵线段树,然后寻找第k个数就可以辣

 

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define N 101000
#define ls(i) T[(i)].ls
#define rs(i) T[(i)].rs
#define w(i) T[(i)].w
struct  node{
    int ls,rs,w;
    node(){ls=0;rs=0;w=0;}
}T[N*20];
int id,n,m,k,t,ans,x,y,z;
int f[N],a[N],b[N],root[N],p[N];
int cmp(int i,int j){
    return a[i]<a[j];
}
void add(int &i,int l,int r,int x){
    T[++id]=T[i];i=id;
    w(i)++;
    if (l==r) return;
    int mid=(l+r)/2;
    if (x<=mid) add(ls(i),l,mid,x);
    else add(rs(i),mid+1,r,x);
}
int find(int x,int y,int l,int r,int k){
    if (l==r) return(l);
    int mid=(l+r)/2;
    int s=w(ls(y))-w(ls(x));
    if (s>=k) return(find(ls(x),ls(y),l,mid,k));
    else return(find(rs(x),rs(y),mid+1,r,k-s));
}
int main(){
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) {scanf("%d",&a[i]);p[i]=i;}
    sort(p+1,p+n+1,cmp);
    for (int i=1;i<=n;i++) b[p[i]]=i;
    for (int i=1;i<=n;i++){
        root[i]=root[i-1];
        add(root[i],1,n,b[i]);
    }
    for (int i=1;i<=m;i++){
        scanf("%d%d%d",&x,&y,&z);
        ans=find(root[x-1],root[y],1,n,z);
        printf("%d\n",a[p[ans]]);
    }
}
Category: 未分类 | Tags: | Read Count: 490

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com