最近做了满多的树状数组的题,这些题的解法不一,实验室的大佬们都会去用分块、莫队算法等等去解决问题,而我解决问题的方式就显得单调了,与Turing Tree【树状数组+map优化(避免了离散化的复杂)】或者是Necklace【HDU 3874】【树状数组】的做法相同,面对这样一道相仿的题,我们依旧是对提问做了个按照H的升序排序,这样我们只需要找ID小于等于目前这个数的值即可了,另外还需要对输入也进行处理,我们记录其值val与它的ID,按照val升序排列,对应只要找到小于等于目前值的ID的个数就是正解了,其中问题提问有(l,r)两个头,即左端点ID与右端点ID,我们要求的answer就是Query(r)-Query(l-1)。
题目链接
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
using namespace std;
typedef long long ll;
const int maxN=1e5+7;
struct node //我们所要询问的问题,左右区间,不妨就对右区间升序排列,然后一一输进去值,找到小于目前r的以及l-1的数个数
{
int l,r,id; //一定要加上id用以标记第几个question
ll h;
}q[maxN];
bool cmp(node e1, node e2) //按照h升序排列
{
return e1.h<e2.h;
}
int N,M;
ll bit[maxN];
struct nnum //输入的值也需要控制其ID
{
ll val, id;
}a[maxN];
bool nnmp(nnum e1, nnum e2)
{
return e1.val<e2.val;
}
void update(int i) //记录的是个数,于是就不需要(i,x)类型,i所代表的就是点与数值
{
while(i<maxN)
{
bit[i]++;
i+=lowbit(i);
}
}
ll Query(int i)
{
ll res=0;
while(i)
{
res+=bit[i];
i-=lowbit(i);
}
return res;
}
ll ans[maxN];
int main()
{
int T;
scanf("%d",&T);
for(int Case=1; Case<=T; Case++)
{
memset(bit, 0, sizeof(bit));
memset(ans, 0, sizeof(ans));
memset(q, 0, sizeof(q));
memset(a, 0, sizeof(a));
scanf("%d%d",&N,&M);
for(int i=1; i<=N; i++)
{
ll e1;
scanf("%lld",&e1);
a[i].val=e1+1;
a[i].id=i;
}
sort(a+1, a+1+N, nnmp);
for(int i=1; i<=M; i++)
{
int e1,e2;
ll e3;
scanf("%d%d %lld",&e1,&e2,&e3);
q[i].l=e1+1;
q[i].r=e2+1;
q[i].h=e3+1;
q[i].id=i;
}
sort(q+1, q+1+M, cmp);
int k=1;
for(int i=1; i<=M; i++)
{
while(k<=N && a[k].val<=q[i].h)
{
update((int)a[k].id);
k++;
}
ans[q[i].id]=Query(q[i].r)-Query(q[i].l-1);
}
printf("Case %d:\n",Case);
for(int i=1; i<=M; i++) printf("%lld\n",ans[i]);
}
return 0;
}