hdu4417(分块+二分)

题目
给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;
}

猜你喜欢

转载自blog.csdn.net/weixin_43342048/article/details/82947690