hdu 4417 Super Mario 划分树+二分

http://acm.hdu.edu.cn/showproblem.php?pid=4417

题意:

给定一个长度为n的序列,求区间[L,R]中小于h的个数;

思路:

分三种情况:

1:如果该区间最小值都大于h输出0;

2:如果该区间最大值小于等于h输出区间长度:

3:否则,二分枚举该区间的第m大,直到找到第m大为最后一个小于等于h的;

View Code
#include <iostream>

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <cmath>

#include <queue>

#include <stack>

#include <set>

#include <map>

#include <string>



#define CL(a,num) memset((a),(num),sizeof(a))

#define iabs(x)  ((x) > 0 ? (x) : -(x))

#define Min(a , b) ((a) < (b) ? (a) : (b))

#define Max(a , b) ((a) > (b) ? (a) : (b))



#define ll __int64

#define inf 0x7f7f7f7f

#define MOD 100000007

#define lc l,m,rt<<1

#define rc m + 1,r,rt<<1|1

#define pi acos(-1.0)

#define test puts("<------------------->")

#define maxn 100007

#define M 100007

#define N 100007

using namespace std;

//freopen("din.txt","r",stdin);

struct node{

    int l,r;

    int mid(){

        return (l + r)>>1;

    }

}tt[N<<2];



int toLeft[20][N],val[20][N];

int sorted[N];

int n,m;

int MIN,MAX;



void build(int l,int r,int rt,int d){

    int i;

    tt[rt].l = l;

    tt[rt].r = r;

    if (l == r) return ;

    int m = tt[rt].mid();

    int lsame = m - l + 1;

    for (i = l; i <= r; ++i){

        if (val[d][i] < sorted[m]) lsame--;

    }



    int lpos = l,rpos = m + 1;

    int same = 0;

    for (i = l; i <= r; ++i){

        if (i == l) toLeft[d][i] = 0;

        else toLeft[d][i] = toLeft[d][i - 1];



        if (val[d][i] < sorted[m]){

            toLeft[d][i]++;

            val[d + 1][lpos++] = val[d][i];

        }

        else if (val[d][i] > sorted[m]){

            val[d + 1][rpos++] = val[d][i];

        }

        else{

            if (same < lsame){

                same++;

                val[d + 1][lpos++] = val[d][i];

                toLeft[d][i]++;

            }

            else{

                val[d + 1][rpos++] = val[d][i];

            }

        }

    }

    build(lc,d + 1);

    build(rc,d + 1);

}

int query(int L,int R,int k,int d,int rt){

    if (L == R) return val[d][L];

    int s,ss;

    if (L == tt[rt].l){

        ss = 0;

        s = toLeft[d][R];

    }

    else{

        ss = toLeft[d][L - 1];

        s = toLeft[d][R] - toLeft[d][L - 1];

    }



    if (s >= k){

        int newl = tt[rt].l + ss;

        int newr = newl + s - 1;

        return query(newl,newr,k,d + 1,rt<<1);

    }

    else{

        int m = tt[rt].mid();

        int bb = L - tt[rt].l - ss;

        int b = R - L + 1 - s;

        int newl = m + bb + 1;

        int newr = newl + b - 1;

        return query(newl,newr,k - s,d + 1,rt<<1|1);

    }

}

int bSearch(int l,int r,int h,int x,int y){

    int ans = 0;

    while (l <= r){

        int m = (l + r)>>1;

        if (query(x,y,m,0,1) > h)

        r = m - 1;

        else{

            l = m + 1;

            ans = m;

        }

    }

    return ans;

}

int Input(){

    char ch = getchar();

    while (ch < '0' || ch > '9') ch = getchar();

    int num = 0;

    while (ch >= '0' && ch <= '9'){

        num = num*10 + ch - '0';

        ch = getchar();

    }

    return num;

}

int main(){

    //freopen("din.txt","r",stdin);

    int t,i;

    int x,y,h;

    int cas = 1;

    t = Input();

    while (t--){

        printf("Case %d:\n",cas++);

        n = Input();

        m = Input();

        for (i = 1; i <= n; ++i){

            val[0][i] = Input();

            sorted[i] = val[0][i];

        }

        sort(sorted + 1,sorted + 1 + n);

        build(1,n,1,0);

        while (m--){

            x = Input();

            y = Input();

            h = Input();

            x++; y++;

            MIN = 1;

            MAX = y - x + 1;

            if (query(x,y,MIN,0,1) > h) puts("0");

            else if (query(x,y,MAX,0,1) <= h) printf("%d\n",MAX);

            else{

                int pos = bSearch(MIN,MAX,h,x,y);

                printf("%d\n",pos);

            }

        }

    }

    return 0;

}

 

你可能感兴趣的:(super)