(离线+树状数组 | 主席树)
题意:给定
n(n<105)
个数
ai(ai<109)
和
m(m<105)
个询问,每次询问求
[l,r]
区间里小于等于
H(H<109)
的数字有多少个?
思路1:我们将数组
ai
从小到大排序,并且将询问依据
H
从小到大进行排序。然后每次枚举到一个询问时,就往树状数组中插入所有小于当前询问里
(注意写while语句插入
思路2:主席树,待更
代码1:
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 100010;
int a[maxn], ans[maxn], tree[maxn];
struct Num {
int num, pos;
Num(){}
Num(int a, int b):num(a),pos(b){}
bool operator < (const Num &A) const {
return num < A.num;
}
}mynum[maxn];
struct Query {
int id, l, r, mx;
Query(){}
Query(int a, int b, int c, int d):id(a),l(b),r(c),mx(d){}
bool operator < (const Query &A)const {
return mx < A.mx;
}
}qu[maxn];
int lowbit(int x) {
return x&(-x);
}
void update(int pos, int num) {
for(int i=pos; i<maxn; i+=lowbit(i))
tree[i] += num;
}
int get_sum(int pos) {
int ret = 0;
for(int i=pos; i>0; i-=lowbit(i))
ret += tree[i];
return ret;
}
int main() {
int T, n, m, cas = 0;
scanf("%d",&T);
while(T --) {
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++) {
scanf("%d",&a[i]);
mynum[i] = Num(a[i], i);
}
sort(mynum+1, mynum+n+1);
for(int i=1; i<=m; i++) {
int l, r, mx;
scanf("%d%d%d",&l,&r,&mx);
qu[i] = Query(i, l+1, r+1, mx);
}
sort(qu+1, qu+m+1);
memset(tree, 0, sizeof(tree));
int cur = 1;
for(int i=1; i<=m; i++) {
while(cur <= n && mynum[cur].num <= qu[i].mx) {
update(mynum[cur].pos, 1);
cur ++;
}
int tot = get_sum(qu[i].r) - get_sum(qu[i].l-1);
//printf("get : %d %d\n",get_sum(qu[i].r),get_sum(qu[i].l-1));
ans[qu[i].id] = tot;
}
printf("Case %d:\n",++cas);
for(int i=1; i<=m; i++)
printf("%d\n",ans[i]);
}
return 0;
}