整体二分
求区间第k大
和快速排序差不多 递归的
#include<stdio.h> #include<algorithm> #include<string.h> #include<math.h> #include<set> #include<string> #include<map> using namespace std; typedef long long LL; #define inf 1e9 #define MAXN 100010 struct node { int x,num; }a[MAXN]; bool cmp(node a,node b) { return a.x<b.x; } struct node1 { int x,y,k,num,cnt; }q[MAXN],b[MAXN]; int sum[MAXN],ans[MAXN]; int n,m; void calc(int ll,int rr,int rawl,int mid) { int L=1,R=n+1,MID; while(L<R) { MID=(L+R)>>1; if(a[MID].x >= rawl) R = MID; else L = MID + 1; } for(int i=R;i<=n&&a[i].x<=mid;i++) for(int j = a[i].num; j <= n;j += (j & -j)) ++sum[j]; for(int i=ll;i<=rr;i++) { q[i].cnt=0; for(int j = q[i].y;j;j -= (j & -j)) q[i].cnt += sum[j]; for(int j = q[i].x - 1;j;j -= (j & -j)) q[i].cnt -= sum[j]; } for(int i = R; i <= n && a[i].x <= mid; i++) for(int j = a[i].num; j <= n; j += (j & -j)) sum[j]--; } void divide(int ll, int rr, int rawL, int rawR) { if(rawL == rawR) { for(int i = ll ; i <= rr ; i++) ans[q[i].num] = rawR; return ; } int mid = (rawL + rawR) >> 1; calc(ll, rr, rawL, mid); int now1,now2; now1=ll; now2=rr; for(int i = ll; i<=rr ; i++) { if(q[i].cnt >= q[i].k) b[now1++] = q[i]; else { q[i].k -= q[i].cnt; b[now2--] = q[i]; } } for(int i = ll; i <= rr; i++) q[i] = b[i]; if(now1 != ll) divide(ll, now1 - 1, rawL, mid); if(now2 != rr) divide(now2 + 1, rr, mid + 1,rawR); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&a[i].x); a[i].num=i; } a[n+1].x=2e9; sort(a+1,a+n+1,cmp); for(int i=1;i<=m;i++) { scanf("%d%d%d",&q[i].x,&q[i].y,&q[i].k); q[i].num=i; } divide(1,m,-inf,inf); for(int i=1;i<=m;i++) printf("%d ",ans[i]); return 0; }