题目:
给n个数,数中有重复的。有m个询问,问的是[L,R] 区间内有多少个数小于等于h。
分析:
快速查找——排序(快排),二分
注意:
二分边界
#include<bits/stdc++.h>
#define maxn 100010
using namespace std;
int n,m,num,block;
int a[maxn],b[maxn],pos[maxn],ls[maxn],rs[maxn];
void reset(int k){
int l=(k-1)*block+1,r=min(k*block,n);
sort(b+l,b+r+1);
ls[k]=l;rs[k]=r;
return ;
}
void work(int x,int y,int h){
int ans=0;
if(pos[x]==pos[y]){
for(int i=x;i<=y;i++)if(a[i]<=h)ans++;
printf("%d\n",ans);
return ;
}
for(int i=pos[x]+1;i<=pos[y]-1;i++){
int left=ls[i],right=rs[i],mid;
while(left<=right){
mid=(left+right)/2;
if(b[mid]<=h)left=mid+1;
if(b[mid]>h)right=mid-1;
}
ans=ans+right-ls[i]+1;
}
for(int i=x;i<=rs[pos[x]];i++)if(a[i]<=h)ans++;
for(int i=ls[pos[y]];i<=y;i++)if(a[i]<=h)ans++;
printf("%d\n",ans);
return ;
}
int main(){
int t;
scanf("%d",&t);
for(int j=1;j<=t;j++){
printf("Case %d:\n",j);
scanf("%d %d",&n,&m);
block=sqrt(n*1.0);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
pos[i]=(i-1)/block+1;
b[i]=a[i];
}
num=n/block;if(n%block!=0)num++;
for(int i=1;i<=num;i++)reset(i);
for(int i=1;i<=m;i++){
int l,r,h;
scanf("%d %d %d",&l,&r,&h);
work(l+1,r+1,h);
}
}
return 0;
}