Question:
There are n numbers and M queries. Each query interval [L, R] contains several numbers smaller than H.
Ideas:
Since n numbers are unchanged, we can use the Division tree to find the k-th small value of any interval in the nlogn complexity (Here we refer to the building)
Each query can be divided into two parts to find the number of the smallest numbers in the range smaller than or equal to H. Then the answer is the number of the second splits.
Total complexity nlogn + M (logn) ^ 2: Build complexity + M queries * each query logn * binary complexity logn
Both N and m are only 10 ^ 5.
Code:
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define N 100010#define M 20int tree[M][N],toleft[M][N],sorted[N];int n,m,t,T;void build(int l,int r,int dep){if(l==r) return ;int i,mid=(l+r)>>1;int y=sorted[mid],same=mid-l+1,lpos=l,rpos=mid+1;for(i=l;i<=r;i++){if(tree[dep][i]<y) same--;}for(i=l;i<=r;i++){if(tree[dep][i]<y) tree[dep+1][lpos++]=tree[dep][i];else if(tree[dep][i]==y&&same>0){tree[dep+1][lpos++]=tree[dep][i];same--;}else tree[dep+1][rpos++]=tree[dep][i];toleft[dep][i]=toleft[dep][l-1]+lpos-l;}build(l,mid,dep+1);build(mid+1,r,dep+1);}int query(int L,int R,int l,int r,int dep,int k){if(l==r) return tree[dep][l];int mid=(L+R)>>1,amt=toleft[dep][r]-toleft[dep][l-1];if(amt>=k){int fl=L+toleft[dep][l-1]-toleft[dep][L-1];int fr=fl+amt-1;return query(L,mid,fl,fr,dep+1,k);}else{int fr=r+toleft[dep][R]-toleft[dep][r];int fl=fr-(r-l-amt);return query(mid+1,R,fl,fr,dep+1,k-amt);}}int main(){ int i,j,l,r,h,fr,ed,md,tmp,ans; while(~scanf("%d",&T)) { for(t=1;t<=T;t++) { printf("Case %d:\n",t); scanf("%d%d",&n,&m); for(i=1;i<=n;i++) { scanf("%d",&sorted[i]); tree[0][i]=sorted[i]; } sort(sorted+1,sorted+1+n); build(1,n,0); while(m--) { scanf("%d%d%d",&l,&r,&h); l++; r++; fr=1; ed=r-l+1; ans=0; while(fr<=ed) { md=(fr+ed)>>1; tmp=query(1,n,l,r,0,md); if(tmp<=h) { fr=md+1; ans=md; } else ed=md-1; } printf("%d\n",ans); } } }return 0;}
HDU 4417 Super Mario