1. 程式人生 > >HDU 4417 (離線線段樹 || 劃分樹 )

HDU 4417 (離線線段樹 || 劃分樹 )

Super Mario

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 6291    Accepted Submission(s): 2715


Problem Description 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
Source

題意:  一行n個數,m次操作 ,每次詢問一個區間內小於k的數有多少個

分析:

1,離線線段樹: 對於詢問預處理,把詢問中的k從小到大進行排序,每次詢問時把小於k的值加入線段樹中,並查詢,最後再輸出。

2,線上劃分樹:對結果進行二分列舉,找出區間有多少第n大值小於等於k的。

1程式碼:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <queue>
#define mem(p,k) memset(p,k,sizeof(p));
#define rep(i,j,k) for(int i=j; i<k; i++)
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define inf 0x6fffffff
#define ll long long
using namespace std;
const int mod=1e9+7;
struct SD{
    int x,w;
    bool operator <(const struct SD &a)const{

        return x<a.x;
    }
}a[110000];
struct node{
    int l,r,h,w;
    bool operator <(const struct node &a)const{
        return h<a.h;
    }
}q[110000];
int f[50000],bk[1100];
int n,m,k,maxx,cur,sum,x,y;
int minn;
int nex[4][2]={0,1,1,0,0,-1,-1,0};
int ans[110000];
int tree[110000<<2];
void update(int k,int l,int r,int rt){
    if(k==l&&k==r){
            tree[rt]=1;return ;
    }
    int m=(l+r)>>1;
    if(k<=m)update(k,lson);
    else update(k,rson);
    tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}
int query(int L,int R,int l,int r,int rt){
    if(L<=l&&r<=R){
        return tree[rt];
    }
    int m=(l+r)>>1,ans=0;
    if(L<=m)ans+=query(L,R,lson);
    if(m<R) ans+=query(L,R,rson);
    return ans;
}
int main()
{
    int t;
    cin>>t;
    int cu=1;
    while(t--){
        cin>>n>>m;
        mem(tree,0);
        rep(i,0,n)scanf("%d",&a[i].x),a[i].w=i;
        sort(a,a+n);
        rep(i,0,m)scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].h),q[i].w=i;
        sort(q,q+m);
        int cur=0;
        for(int i=0;i<m;i++){
            while(cur<n&&a[cur].x<=q[i].h)update(a[cur].w,0,n-1,1),cur++;
            ans[q[i].w]=query(q[i].l,q[i].r,0,n-1,1);
        }
        cout<<"Case "<<cu++<<":"<<endl;
        for(int i=0;i<m;i++){
            printf("%d\n",ans[i]);
        }
    }


    return 0;
}

2程式碼:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <queue>
#define mem(p,k) memset(p,k,sizeof(p));
#define rep(i,j,k) for(int i=j; i<k; i++)
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define inf 0x6fffffff
#define ll long long
using namespace std;
const int mod=1e9+7;
int tree[20][110000],sorted[110000],toleft[20][110000];
int n,m,k,maxx,cur,sum,x,y;
int minn;
int nex[4][2]={0,1,1,0,0,-1,-1,0};

void build(int l,int r,int dep){
    if(l==r)return;
    int m=(l+r)>>1;
    int same=m-l+1;
    for(int i=l;i<=r;i++){
        if(tree[dep][i]<sorted[m])same--;
    }
    int lpos=l,rpos=m+1;
    for(int i=l;i<=r;i++){
        if(tree[dep][i]<sorted[m]){
            tree[dep+1][lpos++]=tree[dep][i];
        }
        else if(tree[dep][i]==sorted[m]&&same){
            tree[dep+1][lpos++]=tree[dep][i];same--;
        }
        else tree[dep+1][rpos++]=tree[dep][i];
        toleft[dep][i]=lpos-l+toleft[dep][l-1];
    }
    build(l,m,dep+1);
    build(m+1,r,dep+1);
}
int query(int L,int R,int l,int r,int dep,int k){
    if(L==R)return tree[dep][L];
    int m=(l+r)>>1;
    int cnt=toleft[dep][R]-toleft[dep][L-1];
    if(cnt>=k){
        int newl=l+toleft[dep][L-1]-toleft[dep][l-1];
        int newr=newl+cnt-1;
        return query(newl,newr,l,m,dep+1,k);
    }
    else{
        int newr=R+toleft[dep][r]-toleft[dep][R];
        int newl=newr-(R-L-cnt);
        return query(newl,newr,m+1,r,dep+1,k-cnt);
    }

}
int main()
{
    int t;
    cin>>t;
    int cu=1;
    while(t--){
        cin>>n>>m;
        mem(tree,0);
        for(int i=1;i<=n;i++){
            scanf("%d",tree[0]+i);
            sorted[i]=tree[0][i];
        }
        sort(sorted+1,sorted+n+1);
        build(1,n,0);
        cout<<"Case "<<cu++<<":"<<endl;
        for(int i=0;i<m;i++){
            scanf("%d%d%d",&x,&y,&k);
            int l=1,r=y-x+1;
            while(l<=r){
                int m=(l+r)>>1;
                if(query(x+1,y+1,1,n,0,m)<=k){
                    l=m+1;
                }
                else r=m-1;
            }
            cout<<r<<endl;
        }

    }


    return 0;
}