# 主席树模板题

## I - Super Mario

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

## 做法：主席树模板

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
using namespace std;
const int N=1e5+55;
int b[N],a[N],pos[N],sum[40*N],sl[40*N],sr[40*N];  //主席树，空间复杂度nlog(n);
int tot=0;                                          //作为动态建树的全局变量；
void build_tree(int &root, int l, int r)              //初始化线段树，动态建树，tot作为dfs序；
{
root=++tot;
sum[root]=0;
if(l==r) return;                              //根节时返回；
int mid=(l+r)>>1;
build_tree(sl[root],l,mid);                     //左右建树；
build_tree(sr[root],mid+1,r);
}
void update(int &root, int l, int r, int last, int p)   //动态建树，节点记录的是该区段数的个数，节点左边记录小于等于当前节点值的个数，右边记录大于当前节点的值;
{
root=++tot;
sl[root]=sl[last];
sr[root]=sr[last];
sum[root]=sum[last]+1;
if(l==r) return ;
int mid=(l+r)>>1;
if(p<=mid) update(sl[root],l,mid,sl[last],p);
else update(sr[root],mid+1,r,sr[last],p);
}
int query(int root, int l, int r, int val)   //dfs查找<=p的个数;
{
if(val<l) return 0;
if(val>=r) return sum[root];
int mid=(l+r)>>1;
if(val<=mid) return query(sl[root],l,mid,val);
else return sum[sl[root]]+query(sr[root],mid+1,r,val);
}
int main()
{
int t,n,m,i,cas=0,ql,qr,h;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
for(i=1;i<=n;++i) scanf("%d",&b[i]),a[i]=b[i];
sort(b+1,b+n+1);
int cnt=1;
for(i=2;i<=n;++i)
if(b[i]!=b[i-1]) b[++cnt]=b[i];            //离散化处理，方便利用线段树维护区间;
build_tree(pos[0],1,cnt);
for(i=1;i<=n;++i){
int p=lower_bound(b+1,b+cnt+1,a[i])-b;
update(pos[i],1,cnt,pos[i-1],p);             //将每一次建树的根节点储存在pos[]数组中用于后面的访问;
}
printf("Case %d:\n",++cas);
for(i=0;i<m;i++){
scanf("%d%d%d",&ql,&qr,&h);
int p=lower_bound(b+1,b+cnt+1,h)-b;      //在离散化时数值有可能对不上，需要找的是<=h的数字，所以p需要upper找大于的数再-1；
if(b[p]!=h) p--;
printf("%d\n",query(pos[qr+1],1,cnt,p)-query(pos[ql],1,cnt,p));   //建树时从1开始编号，查找时从0开始查找;
}
}
return 0;
}

©️2019 CSDN 皮肤主题: 技术工厂 设计师: CSDN官方博客