poj2104
先读入所有数据,离散一遍
从1-n给每个点建立一颗线段树,若询问区间l-r的第k大,则只要让【第r棵树一段前缀区间内点的个数】-【第l-1棵树一段前缀区间内的点的个数】=k(实际上有可能不是等于,而是大于等于,因为可能存在多个相同的数),该区间最后一个数即为答案
#include<cstdio> #include<cctype> #include<algorithm> using namespace std; const int maxn=100010; struct data{int l,r,sz;}tr[maxn<<4]; int n,m,cnt,key,a[maxn],rk[maxn],id[maxn],rt[maxn]; inline int read(int &x){ char ch=getchar();x=0; while(!isdigit(ch))ch=getchar(); while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} } bool cmp(const int &x,const int &y){ return a[x]<a[y]; } void build(int l,int r,int &pos){ tr[++cnt]=tr[pos];pos=cnt;tr[cnt].sz++; if(l==r)return; int mid=(l+r)>>1; if(key<=mid)build(l,mid,tr[cnt].l);else build(mid+1,r,tr[cnt].r); } int query(int l,int r,int x,int y,int k){ if(l==r)return l; int mid=(l+r)>>1,sz=tr[tr[y].l].sz-tr[tr[x].l].sz; if(k<=sz)return query(l,mid,tr[x].l,tr[y].l,k); else return query(mid+1,r,tr[x].r,tr[y].r,k-sz); } int main(){ read(n);read(m); for(int i=1;i<=n;i++){read(a[i]);id[i]=i;} sort(id+1,id+n+1,cmp); for(int i=1;i<=n;i++)rk[id[i]]=i; for(int i=1;i<=n;i++){ rt[i]=rt[i-1]; key=rk[i];build(1,n,rt[i]); } while(m--){ int l,r,k;read(l);read(r);read(k); printf("%d\n",a[id[query(1,n,rt[l-1],rt[r],k)]]); } }