hdu 4417 Super Mario 划分树+二分
http://acm.hdu.edu.cn/showproblem.php?pid=4417
题意:
给定一个长度为n的序列,求区间[L,R]中小于h的个数;
思路:
分三种情况:
1:如果该区间最小值都大于h输出0;
2:如果该区间最大值小于等于h输出区间长度:
3:否则,二分枚举该区间的第m大,直到找到第m大为最后一个小于等于h的;
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <set> #include <map> #include <string> #define CL(a,num) memset((a),(num),sizeof(a)) #define iabs(x) ((x) > 0 ? (x) : -(x)) #define Min(a , b) ((a) < (b) ? (a) : (b)) #define Max(a , b) ((a) > (b) ? (a) : (b)) #define ll __int64 #define inf 0x7f7f7f7f #define MOD 100000007 #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define test puts("<------------------->") #define maxn 100007 #define M 100007 #define N 100007 using namespace std; //freopen("din.txt","r",stdin); struct node{ int l,r; int mid(){ return (l + r)>>1; } }tt[N<<2]; int toLeft[20][N],val[20][N]; int sorted[N]; int n,m; int MIN,MAX; void build(int l,int r,int rt,int d){ int i; tt[rt].l = l; tt[rt].r = r; if (l == r) return ; int m = tt[rt].mid(); int lsame = m - l + 1; for (i = l; i <= r; ++i){ if (val[d][i] < sorted[m]) lsame--; } int lpos = l,rpos = m + 1; int same = 0; for (i = l; i <= r; ++i){ if (i == l) toLeft[d][i] = 0; else toLeft[d][i] = toLeft[d][i - 1]; if (val[d][i] < sorted[m]){ toLeft[d][i]++; val[d + 1][lpos++] = val[d][i]; } else if (val[d][i] > sorted[m]){ val[d + 1][rpos++] = val[d][i]; } else{ if (same < lsame){ same++; val[d + 1][lpos++] = val[d][i]; toLeft[d][i]++; } else{ val[d + 1][rpos++] = val[d][i]; } } } build(lc,d + 1); build(rc,d + 1); } int query(int L,int R,int k,int d,int rt){ if (L == R) return val[d][L]; int s,ss; if (L == tt[rt].l){ ss = 0; s = toLeft[d][R]; } else{ ss = toLeft[d][L - 1]; s = toLeft[d][R] - toLeft[d][L - 1]; } if (s >= k){ int newl = tt[rt].l + ss; int newr = newl + s - 1; return query(newl,newr,k,d + 1,rt<<1); } else{ int m = tt[rt].mid(); int bb = L - tt[rt].l - ss; int b = R - L + 1 - s; int newl = m + bb + 1; int newr = newl + b - 1; return query(newl,newr,k - s,d + 1,rt<<1|1); } } int bSearch(int l,int r,int h,int x,int y){ int ans = 0; while (l <= r){ int m = (l + r)>>1; if (query(x,y,m,0,1) > h) r = m - 1; else{ l = m + 1; ans = m; } } return ans; } int Input(){ char ch = getchar(); while (ch < '0' || ch > '9') ch = getchar(); int num = 0; while (ch >= '0' && ch <= '9'){ num = num*10 + ch - '0'; ch = getchar(); } return num; } int main(){ //freopen("din.txt","r",stdin); int t,i; int x,y,h; int cas = 1; t = Input(); while (t--){ printf("Case %d:\n",cas++); n = Input(); m = Input(); for (i = 1; i <= n; ++i){ val[0][i] = Input(); sorted[i] = val[0][i]; } sort(sorted + 1,sorted + 1 + n); build(1,n,1,0); while (m--){ x = Input(); y = Input(); h = Input(); x++; y++; MIN = 1; MAX = y - x + 1; if (query(x,y,MIN,0,1) > h) puts("0"); else if (query(x,y,MAX,0,1) <= h) printf("%d\n",MAX); else{ int pos = bSearch(MIN,MAX,h,x,y); printf("%d\n",pos); } } } return 0; }