题意:
给你一个长度为n的数组,然后m次查询,每次询问问你l到r区间有多少个数是小于等于H的。
思路:
主席树维护数据,用区间右树小于等于H的数的数量减去区间左树小于等于H的数的数量即可。
代码:
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
#define ls l,mid
#define rs mid+1,r
#define mi (l+r)/2
const int MAXN=1e5+7;
vector <int> a;
typedef struct Node{
int val;
int son[2];
}Node;
Node tree[MAXN*20];
int b[MAXN];
int cnt,pos,rtid[MAXN],ans,enn;
int new_node(){
int rt=++cnt;
tree[rt].val=0;
tree[rt].son[0]=tree[rt].son[1]=0;
return rt;
}
int build(int l,int r){
int rt=new_node();
if(l==r){
return rt;
}
int mid=mi;
tree[rt].son[0]=build(ls);
tree[rt].son[1]=build(rs);
return rt;
}
void update(int l,int r,int rt,int lart){
tree[rt].val=tree[lart].val;
tree[rt].val++;
if(l==r) return ;
int mid=mi;
if(pos>mid){
tree[rt].son[0]=tree[lart].son[0];
tree[rt].son[1]=new_node();
update(mid+1,r,tree[rt].son[1],tree[lart].son[1]);
}else{
tree[rt].son[1]=tree[lart].son[1];
tree[rt].son[0]=new_node();
update(l,mid,tree[rt].son[0],tree[lart].son[0]);
}
}
int query(int l,int r,int rt){
if(l>enn) return 0;
if(r<=enn){
return tree[rt].val;
}
int mid=mi;
return query(ls,tree[rt].son[0])+query(rs,tree[rt].son[1]);
}
void ini(){
a.clear();cnt=0;
}
int main()
{
int n,m,st,en,k,T;
vector <int>::iterator it;
scanf("%d",&T);
for(int Case=1;Case<=T;Case++){
scanf("%d%d",&n,&m);
ini();
for(int i=1;i<=n;i++) scanf("%d",&b[i]),a.push_back(b[i]);
sort(a.begin(),a.end());a.erase(unique(a.begin(),a.end()),a.end());
int len=a.size();
rtid[0]=build(1,len);
for(int i=1;i<=n;i++){
pos=lower_bound(a.begin(),a.end(),b[i])-a.begin()+1;
rtid[i]=++cnt;
update(1,len,rtid[i],rtid[i-1]);
}
printf("Case %d:\n",Case);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&st,&en,&k);
it=upper_bound(a.begin(),a.end(),k);
if(it==a.end()){
enn=len;
}else{
enn=it-a.begin();
}
printf("%d\n",query(1,len,rtid[en+1])-query(1,len,rtid[st]));
}
}
}