1 10 10 0 5 2 7 5 4 3 8 7 7 2 8 6 3 5 0 1 3 1 1 9 4 0 1 0 3 5 5 5 5 1 4 6 3 1 5 7 5 7 3
Case 1: 4 0 0 3 1 2 0 1 5 1 題目意思就是一條線段上有n個點,每個點有個高度值,然後有m組查詢,問你a到b區間裡有多少個數是小於等於h的 這道題的解法為用二分+劃分樹 二分的是第K大數,與高度值進行比較 好久沒1A了。。。。QAQ#include#include #include #include #include #include #include using namespace std; #define MD(x,y) (((x)+(y))>>1) const int maxn = 100000+10; int lftnum[20][maxn]; int num[maxn]; int seg[20][maxn]; int n,m; void build(int L,int R,int dep){ if(L==R) return; int mid = MD(L,R),key = num[mid],lcnt = mid-L+1; for(int i = L; i <= R; i++){ if(seg[dep][i] < key) lcnt--; } int lp = L,rp = mid+1; for(int i = L; i <= R; i++){ if(L==i){ lftnum[dep][i] = 0; }else{ lftnum[dep][i] = lftnum[dep][i-1]; } if(seg[dep][i] < key){ lftnum[dep][i]++; seg[dep+1][lp++] = seg[dep][i]; } else if(seg[dep][i] > key){ seg[dep+1][rp++] =seg[dep][i]; } else{ if(lcnt>0){ lcnt--; lftnum[dep][i]++; seg[dep+1][lp++] = seg[dep][i]; }else{ seg[dep+1][rp++] = seg[dep][i]; } } } build(L,mid,dep+1); build(mid+1,R,dep+1); } int query(int L,int R,int ll,int rr,int dep,int k){ if(L==R) return seg[dep][L]; int a,aa,b,bb; int mid = MD(ll,rr); if(L==ll){ a = 0; aa = lftnum[dep][R] - a; }else{ a = lftnum[dep][L-1]; aa = lftnum[dep][R] - a; } if(aa >= k){ L = ll+a; R = ll+a+aa-1; return query(L,R,ll,mid,dep+1,k); }else{ b = L-ll-a; bb = R-L+1-aa; L = mid+1+b; R = mid+b+bb; return query(L,R,mid+1,rr,dep+1,k-aa); } } int main(){ int ncase,T=1; cin >> ncase; while(ncase--){ scanf("%d%d",&n,&m); for(int i = 1; i <= n; i++){ scanf("%d",&num[i]); seg[0][i] = num[i]; } sort(num+1,num+1+n); build(1,n,0); printf("Case %d:\n",T++); while(m--){ int a,b,h; scanf("%d%d%d",&a,&b,&h); ++a,++b; int l = 1,r = b-a+1; while(l <= r){ int mid = MD(l,r); if(query(a,b,1,n,0,mid) > h){ r = mid-1; }else{ l = mid+1; } } printf("%d\n",r); } } return 0; }