主席树模板题

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;
}
发布了17 篇原创文章 · 获赞 4 · 访问量 858
展开阅读全文

没有更多推荐了,返回首页

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

分享到微信朋友圈

×

扫一扫,手机浏览