主席樹模板題

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章