划分树---hdu4417---区间查找(不)大于h的个数
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
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.
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.)
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
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的个数的更多相关文章
- [csu/coj 1080]划分树求区间前k大数和
题意:从某个区间内最多选择k个数,使得和最大 思路:首先题目给定的数有负数,如果区间前k大出现负数,那么负数不选和更大,于是对于所有最优选择,负数不会出现,所以用0取代负数,问题便转化为区间的前k大数 ...
- 【大杀器】利用划分树秒杀区间内第k大的数
最近看了一道题,大概就是给出一个序列,不断询问其子区间内第k大的数,下面是个截图 绕了一圈没找到中文版题目,if(你是大佬) then 去看截图:else{我来解释:给出一个整数n,和一个整数m,分别 ...
- HDU 3473 Minimum Sum (划分树求区间第k大带求和)(转)
题意:在区间中找一个数,求出该区间每个数与这个数距离的总和,使其最小 找的数字是中位数(若是偶数个,则中间随便哪个都可)接着找到该区间比此数大的数的总和 区间中位数可以使用划分树,然后在其中记录:每层 ...
- [hdu2665]Kth number(划分树求区间第k大)
解题关键:划分树模板题. #include<cstdio> #include<cstring> #include<algorithm> #include<cs ...
- HDOJ题目4417 Super Mario(划分树求区间比k小的个数+二分)
Super Mario Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tota ...
- hdu4417(Super Mario)—— 二分+划分树
Super Mario Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- K-query SPOJ - KQUERY 离线 线段树/树状数组 区间大于K的个数
题意: 给一个数列,一些询问,问你区间$[l.r]$大于$K$的个数 题解: 又一个"人尽皆知傻逼题"? 我们用一个01序列表示当前询问时,该位置的数字是否对答案有贡献, 显然,对 ...
- HDU 4417 Super Mario (划分树)(二分)
Super Mario Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- hdu 4417,poj 2104 划分树(模版)归并树(模版)
这次是彻底把划分树搞明确了,与此同一时候发现了模版的重要性.敲代码一个字符都不能错啊~~~ 划分树具体解释:点击打开链接 题意:求一组数列中随意区间不大于h的个数. 这个题的做法是用二分查询 求给定 ...
随机推荐
- [译]C语言实现一个简易的Hash table(2)
上一章,简单介绍了Hash Table,并提出了本教程中要实现的几个Hash Table的方法,有search(a, k).insert(a, k, v)和delete(a, k),本章将介绍Hash ...
- nRF52832 BLE_DFU空中升级OTA(一)安装软件(SDK14.2.0)
准备工作,需要安装好几个软件,详细的过程请参考下面的文章(http://www.cnblogs.com/iini/p/9314246.html)这里说的非常详细,而且也有工具在云盘,对于初学者非常友好 ...
- restful api编写规范
Node.js 除了用来编写 WEB 应用之外,还可以用来编写 API 服务,我们在本文中会介绍编写 Node.js Rest API 的最佳实践,包括如何命名路由.进行认证和测试等话题,内容摘要如下 ...
- ACM1009:FatMouse' Trade
Problem Description FatMouse prepared M pounds of cat food, ready to trade with the cats guarding th ...
- Python学习之——Oracle数据库连接
一.安装Oracle客户端 1.下载对应安装文件,官网地址:http://www.oracle.com/technetwork/database/database-technologies/insta ...
- 在Linux中安装JDK和IDEA
前言 寒假安装虚拟机的时候我就没有安装好,到学校之后,因为时间紧加上更习惯Windows的操作习惯,我只在Windows上安装了JDK和IDEA,但是随着学习的深入,我发现用虚拟机写命令行.新建jav ...
- 20155337祁家伟 2016-2017-2 《Java程序设计》第2周学习总结
20155337 2016-2017-2 <Java程序设计>第2周学习总结 教材学习内容总结 这周我学习了从JDK到IDE的学习内容,简单来说分为以下几个部分 使用命令行和IDE两种方式 ...
- ELKStack入门篇(三)之logstash收集日志写入redis
1.部署Redis 1.1.下载redis [root@linux-node2 ~]# wget http://download.redis.io/releases/redis-4.0.6.tar.g ...
- Spring学习(一)-----Spring 模块详解
官方下载链接:http://repo.spring.io/release/org/springframework/spring/ Spring 模块详解: Core 模块 spring-beans-3 ...
- javaweb(二十二)——基于Servlet+JSP+JavaBean开发模式的用户登录注册
一.Servlet+JSP+JavaBean开发模式(MVC)介绍 Servlet+JSP+JavaBean模式(MVC)适合开发复杂的web应用,在这种模式下,servlet负责处理用户请求,jsp ...