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. [译]C语言实现一个简易的Hash table(2)

    上一章,简单介绍了Hash Table,并提出了本教程中要实现的几个Hash Table的方法,有search(a, k).insert(a, k, v)和delete(a, k),本章将介绍Hash ...

  2. nRF52832 BLE_DFU空中升级OTA(一)安装软件(SDK14.2.0)

    准备工作,需要安装好几个软件,详细的过程请参考下面的文章(http://www.cnblogs.com/iini/p/9314246.html)这里说的非常详细,而且也有工具在云盘,对于初学者非常友好 ...

  3. restful api编写规范

    Node.js 除了用来编写 WEB 应用之外,还可以用来编写 API 服务,我们在本文中会介绍编写 Node.js Rest API 的最佳实践,包括如何命名路由.进行认证和测试等话题,内容摘要如下 ...

  4. ACM1009:FatMouse' Trade

    Problem Description FatMouse prepared M pounds of cat food, ready to trade with the cats guarding th ...

  5. Python学习之——Oracle数据库连接

    一.安装Oracle客户端 1.下载对应安装文件,官网地址:http://www.oracle.com/technetwork/database/database-technologies/insta ...

  6. 在Linux中安装JDK和IDEA

    前言 寒假安装虚拟机的时候我就没有安装好,到学校之后,因为时间紧加上更习惯Windows的操作习惯,我只在Windows上安装了JDK和IDEA,但是随着学习的深入,我发现用虚拟机写命令行.新建jav ...

  7. 20155337祁家伟 2016-2017-2 《Java程序设计》第2周学习总结

    20155337 2016-2017-2 <Java程序设计>第2周学习总结 教材学习内容总结 这周我学习了从JDK到IDE的学习内容,简单来说分为以下几个部分 使用命令行和IDE两种方式 ...

  8. ELKStack入门篇(三)之logstash收集日志写入redis

    1.部署Redis 1.1.下载redis [root@linux-node2 ~]# wget http://download.redis.io/releases/redis-4.0.6.tar.g ...

  9. Spring学习(一)-----Spring 模块详解

    官方下载链接:http://repo.spring.io/release/org/springframework/spring/ Spring 模块详解: Core 模块 spring-beans-3 ...

  10. javaweb(二十二)——基于Servlet+JSP+JavaBean开发模式的用户登录注册

    一.Servlet+JSP+JavaBean开发模式(MVC)介绍 Servlet+JSP+JavaBean模式(MVC)适合开发复杂的web应用,在这种模式下,servlet负责处理用户请求,jsp ...