标签:
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <cstring> #include <string.h> #include <queue> //hdu4417(划分树)--二分 #define N 100010 using namespace std; int sorted[N], p[20][N], num[20][N]; void build(int l, int r, int n) { if(l==r)return ; int t, count, lr=l, mid, rh; mid=(l+r)>>1; rh=mid+1; for(t=mid, count=0; t>=l; --t) { if(sorted[mid]==sorted[t]) count++; else break; } for(t=l; t<=r; ++t) { num[n][t]=num[n][t-1]; if(p[n][t]==sorted[mid]) { if(count) { count--; p[n+1][lr++]=p[n][t]; num[n][t]++; } else { p[n+1][rh++]=p[n][t]; } } else if(p[n][t]<sorted[mid]) { p[n+1][lr++]=p[n][t]; num[n][t]++; } else p[n+1][rh++]=p[n][t]; } build(l, mid, n+1); build(mid+1, r, n+1); return ; } int query(int n, int l, int r, int ql, int qr, int k) //求在[ql,qr]内第k小的数 { if(l==r)return p[n][l]; int s=0, s1, s2, s3, mid; mid=(l+r)>>1; s1=num[n][qr]-num[n][ql-1]; //[ql,qr]左孩子的个数 s2=num[n][ql-1]-num[n][l-1]; //[l,ql)左孩子的个数 if(k<=s1) { return query(n+1, l, mid, l+s2, l+s1+s2-1, k); } else { s2=ql-l-s2; //[l,ql)右孩子的个数 s3=qr-ql+1-s1; //[ql,qr]右孩子的个数 return query(n+1, mid+1, r, mid+1+s2, mid+s2+s3, k-s1); } } int solve(int a, int b, int c, int n) //二分 { int l=1, r=b-a+1, mid, ans=0, k; //r是这个区间的长度,二分是按在这个区间(a,b)内第几小(名次)来二分的 while(l<=r) { mid=(l+r)>>1; k=query(0, 1, n, a, b, mid); //k第几小的数 if(c>=k) //名次要更后 { ans=mid; l=mid+1; } else r=mid-1; } return ans; } int main() { int n, m, t, T, i, l, r, h; scanf("%d", &T); for(i=1; i<=T; ++i) { scanf("%d%d", &n, &m); for(t=1; t<=n; ++t) { scanf("%d", sorted+t); p[0][t]=sorted[t]; } sort(sorted+1, sorted+n+1); build(1, n, 0); printf("Case %d:\n", i); for(t=0; t<m; ++t) { scanf("%d%d%d", &l, &r, &h); l++; r++; printf("%d\n", solve(l, r, h, n)); } } return 0; }
标签:
原文地址:http://blog.csdn.net/u012432475/article/details/16355455