Super Mario
HDU - 4417
题目要求给出一个区间,求出区间【l,r】之内小于等于给定H的数的个数. 我们可以类比求区间第k大的方法去求区间小于等于H的,
有一个技巧就是先将H读入,将H和原数据一起离散化,但是建树的时候依然只建n棵树,最后每次求一下[0-r] [0-l-1]
做差就可以了(注意题目区间是【0,n-1】)。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
#define N 100000
int a[N*4],b[N*4];
int sum[N*20],T[N*20];
int L[N*20],R[N*20];
int cnt=0;
void build(int &rt,int l,int r)
{
rt=++cnt;
sum[rt]=0;
if(l==r)return ;
int m=(l+r)>>1;
build(L[rt],l,m);
build(R[rt],m+1,r);
}
void update(int &rt,int pre,int l,int r,int x)
{
rt=++cnt;
L[rt]=L[pre],R[rt]=R[pre];
sum[rt]=sum[pre]+1;
if(l==r)return ;
int m=(l+r)>>1;
if(x<=m)update(L[rt],L[pre],l,m,x);
else update(R[rt],R[pre],m+1,r,x);
}
int query(int rt,int l,int r,int k)
{
int ans=0;
while(l<r)
{
int mid=(l+r)>>1;
if(k<mid)
{
rt=L[rt];
r=mid;
}
else
{
ans+=sum[L[rt]];
rt=R[rt];
l=mid+1;
}
}
return ans;
}
int be[N],en[N],H[N];
int main()
{
int t;
scanf("%d",&t);
for(int cas=1;cas<=t;cas++)
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
b[i]=a[i];
}
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&be[i],&en[i],&H[i]);
b[i+n]=H[i];
}
sort(b+1,b+1+n+m);
int len=unique(b+1,b+1+n+m)-b-1;
cnt=0;
build(T[0],1,len);
for(int i=1;i<=n;i++)
{
int pos=lower_bound(b+1,b+1+len,a[i])-b;
update(T[i],T[i-1],1,len,pos);
}
printf("Case %d:\n",cas);
for(int i=1;i<=m;i++)
{
int p1=lower_bound(b+1,b+1+len,H[i])-b;
int k1=query(T[en[i]+1],1,len,p1);
int k2=query(T[be[i]],1,len,p1);
printf("%d\n",k1-k2);
}
}
return 0;
}
参考了大牛的题解发现可以用树状数组离线处理,具体思路是这样的。
对于区间里的每一个值,我们按照从小到大排序,然后我们按照位置依次插入
同样的,对于要查询的H我们也将它从小到大排序,这样我们就能保证,当查询到较大的H时
比H小的值都已经插进树状数组里了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 100005
#define lowb(x) x&-x;
struct node
{
int k,id;
}a[N];
struct node1
{
int l,r,h,id;
}H[N];
int L[N],R[N];
int C[N];
int ans[N];
bool cmp(node x,node y)
{
return x.k<y.k;
}
bool cmp1(node1 x,node1 y)
{
return x.h<y.h;
}
void add(int pos)
{
while(pos<=N)
{
C[pos]+=1;
pos+=lowb(pos);
}
}
int getsum(int x)
{
int ans=0;
while(x)
{
ans+=C[x];
x-=lowb(x);
}
return ans;
}
void solve(int m,int n)
{
int top=1;
for(int i=1;i<=m;i++)
{
while(top<=n&&a[top].k<=H[i].h)
{
add(a[top].id);
top++;
}
// printf("%d %d %d\n",H[i].l,H[i].r,H[i].h);
// printf("%d %d\n",getsum(H[i].l-1),getsum(H[i].r));
ans[H[i].id]=getsum(H[i].r)-getsum(H[i].l-1);
}
for(int i=1;i<=m;i++)
{
printf("%d\n",ans[i]);
}
}
int main()
{
int t;
cin>>t;
for(int cas=1;cas<=t;cas++)
{
int n,m;
memset(C,0,sizeof(C));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i].k);
a[i].id=i;
}
sort(a+1,a+1+n,cmp);
int x,y;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&H[i].h);
H[i].l=x+1,H[i].r=y+1;
H[i].id=i;
}
sort(H+1,H+1+m,cmp1);
printf("Case %d:\n",cas);
solve(m,n);
}
}