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

Super Mario

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 2315    Accepted Submission(s): 1127

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
 

题目大意:在区间[s,t]查找不大于h的有多少个

做法:用划分树二分枚举第K大(具体看下面注释)

注释处有分析在区间[s,t]查找大于h的有多少个 注意融会贯通

#include <iostream>
#include <string.h>
#include <algorithm>
#define maxn 100010
#define mid ((L+R)>>1)
using namespace std;
int tree[20][maxn];//表示每层每个位置的值
int toleft[20][maxn];//20层每层maxn t用来放原序; toleft[p][i]表示第P层第i个放左节点的元素个数
int sorted[maxn];//已经排序的数
//以下为查找区间第k小划分树
void build(int p,int L,int R) //p:第几层 默认0开始 ; L,R 左右区间从[1,n]开始建
{
if(L==R) return; //这个放最上边省时
int lm=0,i,ls=L,rs=mid+1;//lm表示应被放入左子树且与中位数相等的数有多少个,ls为左子树的起始位置,rs为右子树的起始位置
for(i=mid;i>=L;i--) //求lm ;2 3 3 4 4 5 5 7 9得到的lm=2
{
if(sorted[i]==sorted[mid])
lm++; //之前有一个错误的想法: 不记录这个lm 找的时候直接找<=的 但是这样会出错 比如 2 4 4 4 5 1
else // 排序: 1 2 4 4 4 5 那如果我们直接找<=的(6/2=3)个的话 会找到 2 4 4这样就错了所以还是要记录lm
break;
}
for(i=L;i<=R;i++)
{
if(i==L)//这里要特殊讨论(原因:间接的对所有初始化 我们这样做便于toleft[p][i]=toleft[p][i-1]这一部的处理)
toleft[p][i]=0; //
else
toleft[p][i]=toleft[p][i-1];//下一个肯定是上一个+0或1 if(tree[p][i]==sorted[mid])//若与中位数相等则判断是否应该被放入左子树
{
if(lm)
{
lm--;
toleft[p][i]++; //如果满足 说明又多了一个元素放左节点了
tree[p+1][ls++]=tree[p][i];//放入下一个t[]
}
else
tree[p+1][rs++]=tree[p][i];
}
else if(tree[p][i]<sorted[mid])//查找区间第K大即为>
{
toleft[p][i]++;
tree[p+1][ls++]=tree[p][i];
}
else
tree[p+1][rs++]=tree[p][i];
}
build(p+1,L,mid);
build(p+1,mid+1,R);
}
//查询区间第k大的数,[L,R]是大区间,[l,r]是要查询的小区间
int query(int p,int L,int R,int l,int r,int k)
{
int s,ss;//s表示[L,l-1]放入左子树的个数,ss表示区间[l,r]被放入左子树的个数
if(L==R)//找到所求的数
return tree[p][L];
if(l==L)
s=0,ss=toleft[p][r];
else
s=toleft[p][l-1],ss=toleft[p][r]-s;
if(k<=ss)//要找的数在左子树中
return query(p+1,L,mid,L+s,L+toleft[p][r]-1,k);
else//要找的数在右子树中
return query(p+1,mid+1,R,mid+1-L+l-s,mid+1-L+r-toleft[p][r],k-ss);
}
//原理 在区间[s,t]查找不大于h的有多少个,我们先让区间第mid2小的数与他比较;
//如果这个数还小于h 说明现在至少有mid2个数比h小 然后找[(mid2+1)+r]>>1大的数继续比较;
//否则说明这个数比h大;不能判断至少多几个比h小;所以找[l+mid2]>>1大的数继续比较;
int solve(int L,int R,int s,int t,int h){ //在查找区间[s,t]不大于h的个数有多少[L,R]<=>[1,n]
int l=1;
int r=t-s+1;
int mid2;
int ans=0;
while(l<=r){
mid2=(l+r)>>1;
int temp=query(0,L,R,s,t,mid2);//得到区间【s,t】的第mid2小的数
/*
//如果问在查找区间[s,t]大于h的个数有多少
// 方法一:
if(temp>h){ //if第mid2小的数都比h来得大那至少有(t-s+1)-mid2+1个
ans=(t-s+1)-mid2+1;//自己画一下就能够理解了
r=mid2-1;
}
else l=mid2+1;//if第mid2小的数不大于h 往后面找
//方法2:
* query方法改成得到区间【s,t】的第mid2 ****大*****的数(上面有讲只需要改个符号即可)
if(temp>h){ //if第mid2大的数h大;那至少有mid2个数比h大
ans=mid2//
l=mid2+1;//往后找
}
else r=mid2-1;//否则无法知道至少几个,往前面找更大的数与之比较 */
if(temp<=h){
ans=mid2;
l=mid2+1;
}
else r=mid2-1; //注意这里要-1 不然答案出不来 因为while的条件是l<=r 如果不-1会出现 l=r的情况 mid2=l=r无限循环
}
return ans;
}
int main()
{
int T;
int n,m;
int s,t,h;
cin>>T;
int iCase=0;
while(T--)
{ cin>>n>>m;
for(int i=1;i<=n;i++)//从1开始
{
cin>>tree[0][i];
sorted[i]=tree[0][i];
}
sort(sorted+1,sorted+n+1);
build(0,1,n);
cout<<"Case "<<++iCase<<":"<<endl;
while(m--)
{
cin>>s>>t>>h;
s++; //题目的输入是从[0,n-1] 我们数据转化到[1,n]
t++;
cout<<solve(1,n,s,t,h)<<endl;
}
}
return 0;
}
/*
*
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
output:
Case 1:
4
0
0
3
1
2
0
1
5
1 * */

版权声明:本文为博主原创文章,未经博主允许不得转载。

划分树---hdu4417---区间查找(不)大于h的个数的更多相关文章

  1. [csu/coj 1080]划分树求区间前k大数和

    题意:从某个区间内最多选择k个数,使得和最大 思路:首先题目给定的数有负数,如果区间前k大出现负数,那么负数不选和更大,于是对于所有最优选择,负数不会出现,所以用0取代负数,问题便转化为区间的前k大数 ...

  2. 【大杀器】利用划分树秒杀区间内第k大的数

    最近看了一道题,大概就是给出一个序列,不断询问其子区间内第k大的数,下面是个截图 绕了一圈没找到中文版题目,if(你是大佬) then 去看截图:else{我来解释:给出一个整数n,和一个整数m,分别 ...

  3. HDU 3473 Minimum Sum (划分树求区间第k大带求和)(转)

    题意:在区间中找一个数,求出该区间每个数与这个数距离的总和,使其最小 找的数字是中位数(若是偶数个,则中间随便哪个都可)接着找到该区间比此数大的数的总和 区间中位数可以使用划分树,然后在其中记录:每层 ...

  4. [hdu2665]Kth number(划分树求区间第k大)

    解题关键:划分树模板题. #include<cstdio> #include<cstring> #include<algorithm> #include<cs ...

  5. HDOJ题目4417 Super Mario(划分树求区间比k小的个数+二分)

    Super Mario Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Tota ...

  6. hdu4417(Super Mario)—— 二分+划分树

    Super Mario Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  7. K-query SPOJ - KQUERY 离线 线段树/树状数组 区间大于K的个数

    题意: 给一个数列,一些询问,问你区间$[l.r]$大于$K$的个数 题解: 又一个"人尽皆知傻逼题"? 我们用一个01序列表示当前询问时,该位置的数字是否对答案有贡献, 显然,对 ...

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

    Super Mario Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  9. hdu 4417,poj 2104 划分树(模版)归并树(模版)

    这次是彻底把划分树搞明确了,与此同一时候发现了模版的重要性.敲代码一个字符都不能错啊~~~ 划分树具体解释:点击打开链接 题意:求一组数列中随意区间不大于h的个数. 这个题的做法是用二分查询  求给定 ...

随机推荐

  1. 数据采集与分析的那些事——从数据埋点到AB测试

    作者:网易有数郑栋. 一.为什么企业需要一套完善的用户行为埋点和分析平台 产品初创期间,需要分析天使用户的行为来改进产品,甚至从用户行为中得到新的思路或发现来调整产品方向:产品成长过程,通过对用户行为 ...

  2. 报错: WARN hdfs.DFSClient: Caught exception java.lang.InterruptedException

    WARN hdfs.DFSClient: Caught exception java.lang.InterruptedException 而且日志中没有错误. 官网语句:$ bin/hdfs dfs ...

  3. C语言中的强制类型转换

    先直接放程序吧,后面还有总结. -------------------------------------------start------------------------------------ ...

  4. Xilinx FPGA高速串行收发器简介

    1 Overview 与传统的并行实现方法相比,基于串行I/O的设计具有很多优势,包括:器件引脚数较少.降低了板空间要求.印刷电路板(PCB)层数较少.可以轻松实现PCB设计.连接器较小.电磁干扰降低 ...

  5. 基于MATLAB的多项式数据拟合方法研究-毕业论文

    摘要:本论文先介绍了多项式数据拟合的相关背景,以及对整个课题做了一个完整的认识.接下来对拟合模型,多项式数学原理进行了详细的讲解,通过对文献的阅读以及自己的知识积累对原理有了一个系统的认识.介绍多项式 ...

  6. FlexPaper 里的pdf2json.exe 下载地址

    在使用FlexPaper 做在线阅读,需要使用到pdf2json.exe,将PDF转成JSON或者XML格式,网上很少下载的,现在提供一个下载的地址 http://pan.baidu.com/s/1i ...

  7. Mybash实现

    Mybash实现 知识储备: feof是C语言标准库函数,其原型在stdio.h中,其功能是检测流上的文件结束符,如果文件结束,则返回非0值,否则返回0,文件结束符只能被clearerr()清除. 创 ...

  8. 20155337 2016-2017-2 《Java程序设计》第一周学习总结

    20155337 2016-2017-2 <Java程序设计>第一周学习总结 教材学习内容总结 我们主要学习的是JAVA SE平台也就是标准平台-Java SE四个组成部分:JVM .JR ...

  9. easyui-dialog打开多次数据串台问题

    问题: 公司项目最近在用easyui写后台管理系统,发现dialog使用后总会报出莫名奇妙的问题 1.打开多次后数据显示上一次的,表单提交错误或者获取数据错误 2.来回跳转后,会有打开其它dialog ...

  10. ARKit-1

    1.1-AR技术简介 增强现实技术(Augmented Reality,简称 AR),是一种实时地计算摄影机影像的位置及角度并加上相应图像.视频.3D模型的技术,这种技术的目标是在屏幕上把虚拟世界套在 ...