题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4417
题意:给你n个数,m次查询,每次查询询问[l,r]区间内比小于等于h的数的个数。
思路:这一题看网上大部分题解都说用线段树,划分树,主席树什么的,其实这一题也可以用树状数组来求解。相当于离线树状数组。我们先将所有的查询用结构体存起来,按照h从小到大排序。并且将初始的数和其对应的下标用结构体存起来,并且按照值从小到大排序。之后我们遍历所有的查询,每次查询的时候将所有小于q[i].h的值的下标加1,一旦值大于q[i].h,我们便更新答案。因为所有的查询已经按照从小到大排好啦,所以前面更新的对后面的没有影响。
AC代码:
#include <map>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define LL long long
const int maxn = 1e5 + 7;
struct node1 {
int val;
int id;
}a[maxn];
bool cmp1(node1 aa,node1 bb) {
return aa.val < bb.val;
}
struct node2 {
int l,r;
int h;
int id;
}q[maxn];
bool cmp2(node2 aa,node2 bb) {
return aa.h < bb.h;
}
int c[maxn];
int n;
int lowbit(int x) {
return x & (-x);
}
void update(int x,int y) {
for(int i = x ; i <= n ; i += lowbit(i)) {
c[i] += y;
}
}
int query(int x) {
int ans = 0;
for(int i = x ; i > 0 ; i -= lowbit(i)) {
ans += c[i];
}
return ans;
}
int ans[maxn];
int main() {
int T;
scanf("%d",&T);
int cas = 1;
while(T--) {
int m;
scanf("%d%d",&n,&m);
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",&q[i].l,&q[i].r,&q[i].h);
q[i].l++ , q[i].r++;
q[i].id = i;
}
sort(a+1,a+n+1,cmp1);
sort(q+1,q+m+1,cmp2);
memset(c,0,sizeof(c));
int cnt = 1;
for(int i = 1 ; i <= m ; i++) {
while(a[cnt].val <= q[i].h && cnt <= n) {
update(a[cnt].id,1);
cnt++;
}
ans[q[i].id] = query(q[i].r) - query(q[i].l - 1);
}
printf("Case %d:\n",cas++);
for(int i = 1 ; i <= m ; i++) {
printf("%d\n",ans[i]);
}
}
return 0;
}