Mario is world-famous plumber. His “burly” figure and amazing jumping ability reminded in our memory. Now the poor princess is in trouble again and Mario needs to save his lover. We regard the road to the boss’s castle as a line (the length is n), on every integer point i there is a brick on height hi. Now the question is how many bricks in [L, R] Mario can hit if the maximal height he can jump is H.
Input
The first line follows an integer T, the number of test data.
For each test data:
The first line contains two integers n, m (1 <= n <=10^5, 1 <= m <= 10^5), n is the length of the road, m is the number of queries.
Next line contains n integers, the height of each brick, the range is [0, 1000000000].
Next m lines, each line contains three integers L, R,H.( 0 <= L <= R < n 0 <= H <= 1000000000.)
Output
For each case, output “Case X: ” (X is the case number starting from 1) followed by m lines, each line contains an integer. The ith integer is the number of bricks Mario can hit for the ith query.
Sample Input
1
10 10
0 5 2 7 5 4 3 8 7 7
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
Sample Output
Case 1:
4
0
0
3
1
2
0
1
5
1
区间查询<=h的数有几个,用主席树可以直接做,只要修改一下query,二分统计个数即可。
注意砖块高度和跳跃高度都要离散化,空间要开2*10^5。
不过网上的普遍做法是线段树离线处理,确实比主席树巧妙得多,把询问和数据按高度从小到大排序,每次只要把<=h的数据插入线段树,直接查询就行,因为后面插入的>h的高度对前面的答案没有影响,根本没必要记录状态。而查询第k大要用主席树记录所有状态,是因为读取了所有数据才能比较大小。
离线处理还是考验思维的灵活性,多留意是否所有的数据对每次查询都有用。
这次只写了主席树,有空再补一下线段树的写法。
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 200010;
const int M = MAXN * 30;
int x,n,q,m,tot;
int a[MAXN], t[MAXN],b[MAXN],L[MAXN],R[MAXN];
int T[M], lson[M], rson[M], c[M];
void Init_hash()
{
for(int i = 1; i <= n;i++)
t[i] = a[i];
for(int i=1;i<=q;i++)
t[i+n]=b[i];
sort(t+1,t+1+n+q);
m = unique(t+1,t+1+n+q)-t-1;
}
int build(int l,int r)
{
int root = tot++;
c[root] = 0;
if(l != r)
{
int mid = (l+r)>>1;
lson[root] = build(l,mid);
rson[root] = build(mid+1,r);
}
return root;
}
int has(int x)
{
return lower_bound(t+1,t+1+m,x) - t;
}
int update(int root,int pos,int val)
{
int newroot = tot++, tmp = newroot;
c[newroot] = c[root] + val;
int l = 1, r = m;
while(l < r)
{
int mid = (l+r)>>1;
if(pos <= mid)
{
lson[newroot] = tot++; rson[newroot] = rson[root];
newroot = lson[newroot]; root = lson[root];
r = mid;
}
else
{
rson[newroot] = tot++; lson[newroot] = lson[root];
newroot = rson[newroot]; root = rson[root];
l = mid+1;
}
c[newroot] = c[root] + val;
}
return tmp;
}
int query(int left_root,int right_root,int k)
{
int l = 1, r = m, ans = 0;
while( l < r)
{
int mid = (l+r)>>1;
if(mid <= k )
{
ans+=c[lson[left_root]]-c[lson[right_root]];
l = mid+1;
left_root = rson[left_root];
right_root = rson[right_root];
}
else
{
r=mid;
left_root = lson[left_root];
right_root = lson[right_root];
}
}
return ans;
}
int main()
{
//freopen("in.txt","r",stdin);
scanf("%d",&x);
int l,r,k,y=0;
while(x--)
{
y++;
scanf("%d%d",&n,&q);
tot = 0;
for(int i = 1;i <= n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=q;i++){
scanf("%d%d%d",&l,&r,&k);
b[i]=k;
L[i]=l+1;
R[i]=r+1;
}
Init_hash();
T[n+1] = build(1,m);
for(int i = n;i ;i--)
{
int pos = has(a[i]);
T[i] = update(T[i+1],pos,1);
}
printf("Case %d:\n",y);
for(int i=1;i<=q;i++)
{
l=L[i];
r=R[i];
k=has(b[i]);
printf("%d\n",query(T[l],T[r+1],k));
}
}
return 0;
}