hdu 4417 划分树

Super Mario

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

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

题意:

查找指定区间内比x小的数的个数

思路:

稍微修改下划分树,但是不知道为什么一开始想的是二分- -,强行GG。写着很麻烦而且还是错的

划分数能很方便地求出了区间中小于等于第i个数的个数,在这个基础上稍作修改即可


/*
*/

#include <functional>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <Map>
using namespace std;
typedef long long ll;
typedef long double ld;

using namespace std;

const int maxn = 100010;

int tree[20][maxn];
int sorted[maxn];
int toleft[20][maxn];

void build(int l,int r,int dep)  //模拟快排 并记录左树中比i小的个数
{
    if(l == r)
        return;
    int mid = (l+r)>>1;
    int same = mid-l+1;
    for(int i = l; i <= r; i++)
    {
        if(tree[dep][i] < sorted[mid])
            same--;
    }
    int lpos = l;
    int rpos = mid+1;
    for(int i = l; i <= r; i++)
    {
        if(tree[dep][i] < sorted[mid])
        {
            tree[dep+1][lpos++] = tree[dep][i];
        }
        else if(tree[dep][i] == sorted[mid] && same > 0)
        {
            tree[dep+1][lpos++] = tree[dep][i];
            same --;
        }
        else
        {
            tree[dep+1][rpos++] = tree[dep][i];
        }
        toleft[dep][i] = toleft[dep][l-1] + lpos -l;

    }
    build(l,mid,dep+1);
    build(mid+1,r,dep+1);
}


int query(int L,int R,int l,int r,int dep,int k)
{
    if(l == r)
    {
        if(tree[dep][l] <= k)
            return 1;
        return 0;
    }
    int mid = (L+R)>>1;
    int cnt = toleft[dep][r]-toleft[dep][l-1];
    if(sorted[mid] > k)          //如果比分界线小
    {
        int lpos = L+toleft[dep][l-1]-toleft[dep][L-1];
        int rpos = lpos+cnt-1;
        if(rpos >= lpos)
            return query(L,mid,lpos,rpos,dep+1,k);
        return 0;
    }
    else
    {
        int rpos = r+toleft[dep][R]-toleft[dep][r];
        int lpos = rpos-(r-l-cnt);
        return cnt+query(mid+1,R,lpos,rpos,dep+1,k);
    }
}


int main()
{
    int n,m,T;
    int cas = 1;
    scanf("%d",&T);
    while(T--)
    {

        scanf("%d%d",&n,&m);
        for(int i = 1; i <= n; i++)
        {
            scanf("%d",&sorted[i]);
            tree[0][i] = sorted[i];
        }
        sort(sorted+1,sorted+n+1);
        build(1,n,0);

        int l,r,to,ans;
        printf("Case %d:
",cas++);
        while(m--)
        {
            scanf("%d%d%d",&l,&r,&to);
            l++;
            r++;
            ans = query(1,n,l,r,0,to);
            printf("%d
",ans);
        }
    }
    return 0;
}





原文地址:https://www.cnblogs.com/Przz/p/5409636.html