链接 Super Mario
题意:
给出一个数列,每次询问【l , r】中小于k的数有几个。
思路:
分块 ,其实就是一种暴力,不过用起来却很巧妙,就是把整个区间分成 sqrt(n) 块,然后对每个区间进行操作,统计答案。
#include<iostream>
#include<cstdio>
#include<map>
#include<math.h>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e6+7;
int block,init[maxn],aft[maxn],belong[maxn];
int l[maxn],r[maxn],num,t,n,q;
void build(){
block=sqrt(n);
num=n/block;if(n%block) num++;
for(int i=1;i<=num;i++){
l[i]=(i-1)*block+1;r[i]=min(n,i*block); //每个分块的左右端点
sort(aft+l[i],aft+r[i]+1); //每个分块排序
}
for(int i=1;i<=n;i++){
belong[i]=(i-1)/block+1; //求每个点所在分块
}
}
int ask(int ll,int rr,int k){
int ans=0;
int s=belong[ll],e=belong[rr];
if(s==e){ //在同一个分块 直接暴力处理
for(int i=ll;i<=rr;i++){
if(init[i]<=k) ans++;
}
return ans;
}
for(int i=ll;i<=r[s];i++){ //单独处理左端分块
if(init[i]<=k) ans++;
}
for(int i=s+1;i<e;i++){ //处理中间分块,排序后可以很快的用二分查询
ans+=upper_bound(aft+l[i],aft+r[i]+1,k)-aft-l[i];
}
for(int i=l[e];i<=rr;i++){
if(init[i]<=k) ans++;
}
return ans;
}
int main(){
cin>>t;
int ca=1;
while(t--){
cin>>n>>q;
for(int i=1;i<=n;i++){
scanf("%d",&init[i]);
aft[i]=init[i];
}
build();
cout<<"Case "<<ca++<<':'<<endl;
while(q--){
int l,r,k;
scanf("%d%d%d",&l,&r,&k);
cout<<ask(l+1,r+1,k)<<endl;
}
}
}
还有离线的写法
简单来说 就是先把要查询的区间保留下来,然后排个序,从小到大查询,插入值得时候也从小到大插。
#include<iostream>
#include<cstdio>
#include<map>
#include<math.h>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
typedef unsigned long long ll;
const int maxn=2e6+7;
struct node{
int l,r,val,id;
}b[maxn];
struct stu{
int id,val;
}a[maxn];
int c[maxn],n,m,T,ans[maxn],ca=1;
bool cmp1(node a,node b){
return a.val<b.val;
}
bool cmp2(stu a,stu b){
return a.val<b.val;
}
int lowbit(int x){
return x&(-x);
}
void update(int x){
while(x<=n){
c[x]+=1;
x+=lowbit(x);
}
}
int getsum(int x){
int sum=0;
while(x>0){
sum+=c[x];
x-=lowbit(x);
}
return sum;
}
int main (){
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
memset(c,0,sizeof(c));
for(int i = 1; i <= n; i ++){
scanf("%d",&a[i].val);
a[i].id=i;
}
for(int i = 1; i <= m; i ++){
scanf("%d%d%d",&b[i].l,&b[i].r,&b[i].val);
b[i].l++,b[i].r++;
b[i].id=i;
}
sort(a+1,a+n+1,cmp2);
sort(b+1,b+m+1,cmp1);
int k=1;
for(int i = 1; i <= m; i ++){
while(k <= n && a[k].val <= b[i].val){
update(a[k].id);
k++;
}
ans[b[i].id]=getsum(b[i].r)-getsum(b[i].l-1);
}
printf ("Case %d:\n",ca++);
for(int i = 1; i <= m; i ++){
printf ("%d\n",ans[i]);
}
}
}