主席树模板题

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

做法:主席树模板

题意:找区间[l,r]中小于等于h的个数;

#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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值