题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4417
题目大意:
给一段序列,问你l r区间之间有多少个小于等于h的数。
解题思路:
可以用离线来做,这里还是用主席树操作,主席树其实蛮简单的,主席树维护出来的本身就是个数,直接求小于等于k的数的个数就好,这里有个地方倒是蛮坑的。
Ac代码:
#include<bits/stdc++.h>
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
const int INF=1e9+7;
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
int n,m,cnt;
int a[maxn],root[maxn];
vector<int> v;
struct node
{
int l,r,sum;
}t[maxn*40];
int getid(int x) {return lower_bound(v.begin(),v.end(),x)-v.begin()+1;}
void update(int l,int r,int &x,int y,int pos) //主席树基本操作
{
t[++cnt]=t[y],t[cnt].sum++,x=cnt;
if(l==r)
return ;
int m=(l+r)>>1;
if(pos<=m)
update(l,m,t[x].l,t[y].l,pos);
if(pos>m)
update(m+1,r,t[x].r,t[y].r,pos);
}
int query(int l,int r,int x,int y,int k) //返回小于等于k的个数
{
if(l==r)
return t[y].sum-t[x].sum;
int m=(l+r)>>1;
int s=t[t[y].l].sum-t[t[x].l].sum;
if(k<=m)
return query(l,m,t[x].l,t[y].l,k);
if(k>m)
return s+query(m+1,r,t[x].r,t[y].r,k);
}
int main()
{
int QAQ,kase=0;
scanf("%d",&QAQ);
while(QAQ--)
{
cnt=0,v.clear();
memset(root,0,sizeof root);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),v.push_back(a[i]);
sort(v.begin(),v.end()),v.erase(unique(v.begin(),v.end()),v.end());
for(int i=1;i<=n;i++)
update(1,n,root[i],root[i-1],getid(a[i]));
printf("Case %d:\n",++kase);
while(m--)
{
int l,r,k;
scanf("%d%d%d",&l,&r,&k);
int p=upper_bound(v.begin(),v.end(),k)-v.begin()-1; //找到应该查询的位置
l++,r++;
if(p>=0) //注意这里要考虑一下边界
printf("%d\n",query(1,n,root[l-1],root[r],p+1));
else
printf("0\n");
}
}
//system("pause");
}