1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <string> #define int long long using namespace std; const int maxn=200005; const int INF=1e9; struct tree{ int ls,rs; int sum; }t[maxn*20]; int n,m; int c,tot; int a[maxn],b[maxn],root[maxn]; int build(int l,int r)//建树 { int p=++tot;//新增一个节点 t[p].sum=0; if(l==r) return p; int mid=(l+r)>>1; t[p].ls=build(l,mid); t[p].rs=build(mid+1,r); return p; } int insert(int now,int l,int r,int x,int delta) { int p=++tot;//新开一个节点 t[p]=t[now]; if(l==r) { t[p].sum+=delta;//在副本上进行加减,保留了历史版本 return p; } int mid=(l+r)>>1; if(x<=mid) t[p].ls=insert(t[now].ls,l,mid,x,delta); else t[p].rs=insert(t[now].rs,mid+1,r,x,delta); t[p].sum=t[t[p].ls].sum+t[t[p].rs].sum; return p; } int ask(int p,int q,int l,int r,int k)//表示在p,q两个节点上,值域为[l,r],求第k小的数 { if(l==r) return l;//左端点等于右端点,找到了答案 int mid=(l+r)>>1; int lcnt=t[t[p].ls].sum-t[t[q].ls].sum; if(k<=lcnt) return ask(t[p].ls,t[q].ls,l,mid,k); else return ask(t[p].rs,t[q].rs,mid+1,r,k-lcnt); } signed main() { cin>>n>>m; for(int i=1;i<=n;i++) { cin>>a[i]; b[++c]=a[i]; } sort(b+1,b+c+1);//离散化 c=unique(b+1,b+c+1)-(b+1); root[0]=build(1,c); for(int i=1;i<=n;i++) { int x=lower_bound(b+1,b+c+1,a[i])-b;//离散化continuing root[i]=insert(root[i-1],1,c,x,1); } for(int i=1;i<=m;i++) { int l,r,k; cin>>l>>r>>k; int ans=ask(root[r],root[l-1],1,c,k); cout<<b[ans]<<'\n'; } return 0; }
|