poj 2104(线段树)
| Time Limit: 20000MS | Memory Limit: 65536K | |
| Total Submissions: 45653 | Accepted: 15177 | |
| Case Time Limit: 2000MS | ||
Description
That is, given an array a[1...n] of different integer numbers, your
program must answer a series of questions Q(i, j, k) in the form: "What
would be the k-th number in a[i...j] segment, if this segment was
sorted?"
For example, consider the array a = (1, 5, 2, 6, 3, 7, 4). Let the
question be Q(2, 5, 3). The segment a[2...5] is (5, 2, 6, 3). If we sort
this segment, we get (2, 3, 5, 6), the third number is 5, and therefore
the answer to the question is 5.
Input
first line of the input file contains n --- the size of the array, and m
--- the number of questions to answer (1 <= n <= 100 000, 1 <=
m <= 5 000).
The second line contains n different integer numbers not exceeding 109 by their absolute values --- the array for which the answers should be given.
The following m lines contain question descriptions, each
description consists of three numbers: i, j, and k (1 <= i <= j
<= n, 1 <= k <= j - i + 1) and represents the question Q(i, j,
k).
Output
Sample Input
7 3
1 5 2 6 3 7 4
2 5 3
4 4 1
1 7 3
Sample Output
5
6
3
转自:http://blog.csdn.net/famousdt/article/details/7064866
建树的过程比较简单,对于区间[l,r],首先通过对原数组的排序找到这个区间的中位数a[mid],小于a[mid]的数划入它的左子树[l,mid-1],大于它的划入右子树[mid,r]。
同时,对于第i个数a[i],记录在[l,i]区间内有多少数被划入左子树。最后,对它的左子树区间[l,mid-1]和右子树区间[mid,r]递归的继续建树就可以了。
建树的时候要注意,对于被分到同一子树的元素,元素间的相对位置不能改变。
查找的过程中主要问题就是确定将要查找的区间。
查找深度为dep,在大区间[L ,R]中找小区间[l ,r]中的第k元素。
我们的想法是,先判断[l ,r]中第k元素在[L ,R]的哪个子树中,然后找出对应的小区间和k,递归的进行查找,直到小区间的l==r为止。
通过之前的记录可以知道,在区间[L,l-1]中有(toleft[dep][l-1]-toleft[dep][L-1])进入左子树,
记它为x。
同理区间[L,r]中有(toleft[dep][r]-toleft[dep][L-1])个数进去左子树,记它为y。
所以,我们知道区间小区间[l,r]中有(y-x)个数进入左子树。那么如果(y-x)>=k,那么就在左子树中继续查找,否则就在右子树中继续查找。
接着,解决查找的小区间的问题。
如果接下来要查找的是左子树,那么小区间应该是[L+([L,l-1]区间进入左子树的个数),L+([L,r]区间内进入左子树的个数)-1]。即区间[L+x,L+y-1]。(这里的-1应该是防止边界问题)
显然,这里k不用变。
如果接下来要查找的是右子树,那么小区间应该是[mid+([L,l-1]区间中进入右子树的个数),mid+([L,r]区间进入右子树的个数)-1]。
即区间[mid+(l-L-x),mid+(r-L-y)]。(这里要记得+1)
显然,这里k要减去区间里已经进入左子树的个数,即k变为k-(y-x)。
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
const int MAXSIZE = ;
int tree[][MAXSIZE]; ///树最多也就30层
int _sort[MAXSIZE];
int toleft[][MAXSIZE]; void build(int l,int r,int deep)
{
if(l==r) return;
int mid =(l+r)>>;
int same = mid-l+; ///设这个变量的主要原因是判断tree[deep][i]==_sort[mid]时tree[deep][i]往哪边走
for(int i=l; i<=r; i++)///计算放于左子树中与中位数相等的数字个数,
{
// printf("%d ",tree[deep][i]);
if(tree[deep][i]<_sort[mid]) same--;
}
//printf("\n");
int left = l;
int right = mid+;
for(int i=l; i<=r; i++)
{
int flag = ;
if((tree[deep][i]<_sort[mid])||(tree[deep][i]==_sort[mid]&&same>))
{
flag = ;
tree[deep+][left++] = tree[deep][i];
if(tree[deep][i]==_sort[mid]) same--;
}
else
{
tree[deep+][right++] = tree[deep][i];
}
toleft[deep][i] = toleft[deep][i-]+flag;
}
build(l,mid,deep+);
build(mid+,r,deep+);
} int query(int L,int R,int l,int r,int k,int deep)
{
if(l==r) return tree[deep][l];
int x = toleft[deep][l-]-toleft[deep][L-]; ///x代表[L,l-1]区间内进入左子树的数字的量
int y = toleft[deep][r]- toleft[deep][L-]; ///y代表[L,r]区间内进入左子树的数字的量
int cnt = y-x; ///cnt代表[l,r]区间内进入左子树的数字的量
int mid = (L+R)>>;
int rx = l - L - x;///l左边放在右子树中的数字个数
int ry = r - L - y;///到r右边为止位于右子树的数字个数
if(cnt>=k)
{
query(L,mid,L+x,L+y-,k,deep+);
}else{
query(mid+,R,mid+rx+,mid+ry+,k-cnt,deep+);
} }
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{ memset(toleft,,sizeof(toleft));
for(int i=; i<=n; i++)
{
scanf("%d",&_sort[i]);
tree[][i] = _sort[i];
} sort(_sort+,_sort+n+);
build(,n,);
while(m--)
{
int a,b,k;
scanf("%d%d%d",&a,&b,&k);
int t = query(,n,a,b,k,);
printf("%d\n",t);
}
}
return ;
}
poj 2104(线段树)的更多相关文章
- K-th Number Poj - 2104 主席树
K-th Number Poj - 2104 主席树 题意 给你n数字,然后有m次询问,询问一段区间内的第k小的数. 解题思路 这个题是限时训练做的题,我不会,看到这个题我开始是拒绝的,虽然题意清晰简 ...
- poj 2886 线段树+反素数
Who Gets the Most Candies? Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 12744 Acc ...
- [poj 2104]主席树+静态区间第k大
题目链接:http://poj.org/problem?id=2104 主席树入门题目,主席树其实就是可持久化权值线段树,rt[i]维护了前i个数中第i大(小)的数出现次数的信息,通过查询两棵树的差即 ...
- K-th Number POJ - 2104 划分树
K-th Number You are working for Macrohard company in data structures department. After failing your ...
- poj 3468(线段树)
http://poj.org/problem?id=3468 题意:给n个数字,从A1 …………An m次命令,Q是查询,查询a到b的区间和,c是更新,从a到b每个值都增加x.思路:这是一个很明显的线 ...
- POJ——3264线段树
题目: 输入两个数(m,n),m表示牛的头数,n表示查询的个数.查询时输入两个数(x,y),表示查询范围的起始值和终止值,查询结果是,这个区间内牛重量的最大值减去牛重量的最小值,数量级为1000,00 ...
- POJ 2828 线段树(想法)
Buy Tickets Time Limit: 4000MS Memory Limit: 65536K Total Submissions: 15422 Accepted: 7684 Desc ...
- poj 2828 线段树
http://poj.org/problem?id=2828 学到的思维: 1.变化的或者后来的优先影响前面的,那么从最后一个往前看,最后一个就成了 确定的, 而且后来的也能够确定----假设从前往后 ...
- POJ - 1177 线段树
POJ - 1177 扫描线 这道题也算是一道扫描线的经典题目了. 只不过这道题是算周长,非常有意思的一道题.我们已经知道了,一般求面积并,是如何求的,现在我们要把扫描线进行改造一下,使得能算周长. ...
- poj 2886 (线段树+反素数打表) Who Gets the Most Candies?
http://poj.org/problem?id=2886 一群孩子从编号1到n按顺时针的方向围成一个圆,每个孩子手中卡片上有一个数字,首先是编号为k的孩子出去,如果他手上的数字m是正数,那么从他左 ...
随机推荐
- 用户登录拦截器查询到登录用户后如何将用户信息传递到后面的Controller
taotao创建订单代码中之前忘了加入用户信息,那么加上呢? 分析:用户创建订单的时候,我们会强制要求用户先登录,也就是说,创建订单的Controller执行时,一定是用户已经登录了的,而用户只要登录 ...
- train val test区别
train是训练集,val是训练过程中的测试集,是为了让你在边训练边看到训练的结果,及时判断学习状态.test就是训练模型结束后,用于评价模型结果的测试集.只有train就可以训练,val不是必须的, ...
- 使用snmp4j实现Snmp功能(一)
相关链接:Snmp学习笔记使用snmp4j实现Snmp功能(一)使用snmp4j实现Snmp功能(二)使用snmp4j实现Snmp功能(三) 上一篇文章讲了Snmp的一些基本概念(Snmp学习笔记), ...
- Spring 容器AOP的实现原理——动态代理
参考:http://wiki.jikexueyuan.com/project/ssh-noob-learning/dynamic-proxy.html(from极客学院) 一.介绍 Spring的动态 ...
- ASP.Net初级学习一(基本语句入门)
<body > <form method="post" action="program.ashx"> <input type=&q ...
- javascript功能封装
实现方式其实很简单,我在代码打上注释,大家就懂了! var _date=[],dateData=["1月","2月","3月",&qu ...
- 【Android】完善Android学习(三:API 3.0)
备注:之前Android入门学习的书籍使用的是杨丰盛的<Android应用开发揭秘>,这本书是基于Android 2.2API的,目前Android已经到4.4了,更新了很多的API,也增 ...
- Spark的Shuffle过程介绍
Spark的Shuffle过程介绍 Shuffle Writer Spark丰富了任务类型,有些任务之间数据流转不需要通过Shuffle,但是有些任务之间还是需要通过Shuffle来传递数据,比如wi ...
- async和await关键词用于定义原生的协程
#python为了将语义变得更加明确,就引入了async和await关键词用于定义原生的协程 # async def downloader(url): # return "xxxx" ...
- Centos 6.5下安装vsftpd服务器
1.查看是否安装vsftp [root@localhost ~]#rpm -qa|grep vsftpd 如果出现 vsftpd-2.2.2-13.el6_6.1.x86_64 则说明已经安装了v ...