样例输入:
1
10 10
5 3 6 2 1 0 8 6 3 4
2 8 6
3 5 0
1 3 1
1 9 4
0 1 0
3 5 5
5 5 1
4 6 3
1 5 7
5 7 3
样例输出:
Case 1: 6 1 0 6 0 3 1 2 5 1 题目大意:
T组输入,每次给定n个不同的高度,q次询问,每次询问输出询问区间高度小于等于询问高度的个数。
解题思路:
题目初看很简单,但是每次遍历必定会T,这个时候,我们就需要用到树状数组了,按照树状数组求逆序对的方法,进行从小到大插入到相应位置一个1,在此之前,我们肯定要把输入的一串数字从小到大排序,同时还需记住他们原来的位置,接着由于是q次询问,我们如果询问一次,就重新从小到大更新树状数组,又显得很繁琐,而且也可能会T,这个时候,我们就需要离线操作,将询问按询问高度排个序,这样就不用重复操作了,我们从第一个询问开始遍历,这个时候就有两种情况,如果前一次询问高度与当前询问高度不同,我们就需要遍历给定数组,在数组元素不超过询问高度的前提下,进行树状数组插入操作,即在元素对应位置插入1,这样就满足,计算的区间内,比询问高度高的还未插入,数组位置为0,而小于等于询问高度的地方插入为1,区间和就是小于等于询问高度的个数;这是一种情况,还有一种情况就是前一次询问高度与当前询问高度相同,这个时候显然我们就不需要更新树状数组,直接计算答案就行了。计算好答案,再按询问次序排列输出答案就行了,同时,此题还有个坑就是它位置是从0开始计算的,所以输入的询问区间,让右边界+1,左边界不用+1,因为计算区间和本身就要让左边界-1。
AC代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
using LL=long long;
#define N (int)1e5+5
int n,m;
int tree[2*N];
struct node{//存储给定数组
int i;
LL val;
}pos[N];
struct _node{//存储询问信息
int l,r;
int idx;
LL h;
int ans;
}q[N];
bool cmp(struct node a,struct node b)
{
return a.val<b.val;
}
bool cmp1(struct _node a,struct _node b)
{
return a.h<b.h;
}
bool cmp2(struct _node a,struct _node b)
{
return a.idx<b.idx;
}
int lowbit(int x)
{
return x&-x;
}
void update(int idx)
{
while(idx<=n)
{
tree[idx]++;
idx+=lowbit(idx);
}
}
int query(int idx)
{
int res=0;
while(idx)
{
res+=tree[idx];
idx-=lowbit(idx);
}
return res;
}
int main()
{
int t;
scanf("%d",&t);
for (int z=1; z<=t; z++) {
scanf("%d%d",&n,&m);
for (int i=1; i<=n; i++) {
scanf("%lld",&pos[i].val);
pos[i].i=i;//存储位置
}
sort(pos+1, pos+n+1, cmp);//给定数组按从小到大排序
for (int i=1; i<=m; i++) {
scanf("%d%d%lld",&q[i].l,&q[i].r,&q[i].h);
q[i].r++;//右边界+1
q[i].idx=i;//记录询问次序
}
sort(q+1, q+m+1, cmp1);//按询问高度排序
q[0].h=-1;//初始化q[0].h为-1,防止q[1].h为0导致没更新树状数组,影响计算
for (int i=1,j=1; i<=m; i++) {
if(q[i].h!=q[i-1].h)
{
while(pos[j].val<=q[i].h&&j<=n)//当前询问高度不等于前一次询问高度时,更新树状数组
{
update(pos[j].i);
j++;
}
}
q[i].ans=query(q[i].r)-query(q[i].l);//计算答案,l由于输入时没+1,所以这里不用-1
}
sort(q+1, q+m+1, cmp2);//按询问次序排序
printf("Case %d:\n",z);
for (int i=1; i<=m; i++) {
printf("%d\n",q[i].ans);
}
memset(tree, 0, sizeof(tree));//树状数组归零
}
return 0;
}