HDU 4417 Super Mario (划分树)(二分)

Super Mario

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

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

【分析】给你一系列数,求给定区间内不大于h的数的个数。直接二分枚举位置然后划分树查找就行了。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <time.h>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#define met(a,b) memset(a,b,sizeof a)
#define pb push_back
#define lson(x) ((x<<1))
#define rson(x) ((x<<1)+1)
using namespace std;
typedef long long ll;
const int N=1e5+50;
const int M=N*N+10;
long long ans;
struct P_Tree {
    int n;
    int tree[20][N];
    int sorted[N];
    int toleft[20][N];
    ll sum[N];
    ll lsum[20][N];

    void init(int len) {
        n=len;
        sum[0]=0;
        for(int i=0; i<20; i++)tree[i][0]=toleft[i][0]=lsum[i][0]=0;
        for(int i=1; i<=n; i++) {
            scanf("%d",&sorted[i]);
            tree[0][i]=sorted[i];
            sum[i]=sum[i-1]+sorted[i];
        }
        sort(sorted+1,sorted+n+1);
        build(1,n,0);
    }
    void build(int l,int r,int dep) {
        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];
                lsum[dep][i] = lsum[dep][i-1] + tree[dep][i];
            } else if(tree[dep][i] == sorted[mid] && same > 0) {
                tree[dep+1][lpos++] = tree[dep][i];
                lsum[dep][i] = lsum[dep][i-1] + tree[dep][i];
                same --;
            } else {
                tree[dep+1][rpos++] = tree[dep][i];
                lsum[dep][i] = lsum[dep][i-1];
            }
            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)return tree[dep][l];
        int mid=(L+R)>>1;
        int cnt=toleft[dep][r]-toleft[dep][l-1];
        int s=toleft[dep][l-1]-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(L,mid,newl,newr,dep+1,k);//×¢òa
        } else {
            ans+=(ll)(lsum[dep][r]-lsum[dep][l-1]);
            //printf("l:  %d   r:   %d  ans:  %lld   %lld  %lld\n",l,r,ans,lsum[dep][r],lsum[dep][l-1]);
            int newr=r+toleft[dep][R]-toleft[dep][r];
            int newl=newr-(r-l-cnt);
            return query(mid+1,R,newl,newr,dep+1,k-cnt);//×¢òa
        }
    }
} tre;
int main() {
    int iCase=0;
    int n,m,k,T;
    int l,r,h;
    scanf("%d\n",&T);
    while(T--) {
        scanf("%d%d",&n,&m);
        tre.init(n);
        printf("Case %d:\n",++iCase);
        while(m--) {
            int Ans=0;
            ans=0;
            scanf("%d%d%d",&l,&r,&h);
            l++;
            r++;
            int ll=1,rr=(r-l)+1;
            while(rr-ll>=0){
                k=(rr+ll)/2;
                int res=tre.query(1,n,l,r,0,k);
                if(res>h)rr=k-1;
                else {
                    Ans=k;
                    ll=k+1;
                }
                //printf("l: %d r: %d k: %d ans: %d\n",l,r,k,Ans);system("pause");
            }
            printf("%d\n",Ans);
        }
    }
    return 0;
}
时间: 2024-08-13 03:31:36

HDU 4417 Super Mario (划分树)(二分)的相关文章

HDU 4417 Super Mario(划分树问题求不大于k的数有多少)

Super Mario Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3625    Accepted Submission(s): 1660 Problem Description Mario is world-famous plumber. His “burly” figure and amazing jumping ability

HDU 4417 Super Mario 划分树/树状数组

题目大意:给定一个序列,求区间内小于等于某数的元素数量 首先区间排名一看就是划分树 不过和第k小不一样 我们需要做一些处理 第一种处理方式是二分答案 然后转换成区间第k小 好方法我喜欢 但是这里说的不是这种方法 首先建树,然后对于每个询问,我们讨论k与a[mid]的关系 若k<a[mid],则右子树一定没有小于等于k的数,我们进入左子树查找 若k>=a[mid],则左子树内一定所有数都小于等于k,于是我们将查询区间中进入左子树的元素的数量记入ans,然后查找右区间 递归退出条件是查询区间为空或

hdu 4417 Super Mario(离线树状数组|划分树)

Super Mario Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2584    Accepted Submission(s): 1252 Problem Description Mario is world-famous plumber. His "burly" figure and amazing jumping a

HDU 4417 Super Mario 主席树查询区间小于某个值的个数

#include<iostream> #include<string.h> #include<algorithm> #include<stdio.h> #include<vector> #define LL long long #define rep(i,j,k) for(int i=j;i<=k;i++) #define per(i,j,k) for(int i=j;i>=k;i--) #define pb push_back #d

hdu 4417 Super Mario (线段树+离线)

题意: n个砖块,第i个砖块的高度是hi. m个query,每个query的格式:L R H (输出[L,R]中有多少个hi小于等于H[即玛里奥能跳过多少块砖]) 数据范围: 1 <= n <=10^5, 1 <= m <= 10^5 Next line contains n integers, the height of each brick, the range is [0, 1000000000]. ( 0 <= L <= R < n 0 <= H &

HDU 4417 Super Mario ( 超级马里奥 + 主席树 + 线段树/树状数组离线处理 + 划分树 )

HDU 4417 - Super Mario ( 主席树 + 线段树/树状数组离线处理 + 划分树 ) 这道题有很多种做法,我先学习的是主席树.后面陆续补上线段树离线和划分树 题目大意就是给定一个区间给定一个数列,每次要求你查询区间[L,R]内不超过K的数的数量 主席树做法: 最基本的是静态第k大,这里是求静态的 <= K,差不多,在Query操作里面需要修改修改 先建立size棵主席树,然后询问的时候统计的是 第R棵主席树中[1,K]的数量 - 第L-1棵主席树中[1,K]的数量 注意这里下标

HDU-4417-Super Mario(划分树+二分)

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 l

【划分树+二分】HDU 4417 Super Mario

第一次 耍划分树.. . 模板是找第k小的 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <string> #include <iostream> #include <algorithm> using namespace std; #include <queue> #include &l

HDU 4417 Super Mario(主席树求区间内的区间查询+离散化)

Super Mario Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5101    Accepted Submission(s): 2339 Problem Description Mario is world-famous plumber. His “burly” figure and amazing jumping abilit