hdu2665 && poj2104划分树
| Time Limit: 20000MS | Memory Limit: 65536K | |
| Total Submissions: 47066 | Accepted: 15743 | |
| 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
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
6
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define INF 1000000001
#define MOD 1000000007
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pi acos(-1.0)
using namespace std;
const int MAXN = ;
int num[][MAXN],cnt[][MAXN];//num[d][i]表示深度为d第i个数 cnt[d][i]表示深度为d第i个数之前(包括第i个数)小于sor[m]的个数
int n,sor[MAXN];//sor[i]表示快排后的数组
void build(int l,int r,int d)
{
if(l == r){
return ;
}
int m = (l + r) >> ;
int same_m = m - l + ;//same_m表示在[l,r]中和sor[m]相同值得个数 如果有多个sor[m]的值,那么有一部分会放到左孩子。
//这里就是求放到左孩子的值为sor[m]的个数
for(int i = l; i <= r; i++){
if(num[d][i] < sor[m])same_m --;
}
int pl,pr;
int cnt_small = ;//表示当前小于sor[m]的个数
pl = l,pr = m + ;//左右孩子开始的位置
for(int i = l; i <= r; i++){
if(num[d][i] < sor[m]){//如果当前值比sor[m]小 那么会放在左孩子
num[d+][pl++] = num[d][i];
cnt_small ++;
cnt[d][i] = cnt_small;
}
else if(num[d][i] == sor[m] && same_m){//如果当前的值和sor[m]相同,那么就要判断左边的sor[m]是否放满了
same_m --;
cnt_small ++;
cnt[d][i] = cnt_small;
num[d+][pl++] = num[d][i];
}
else {//放右孩子 由于右孩子都比sor[m]大,所以cnt_small不需要加
num[d+][pr++] = num[d][i];
cnt[d][i] = cnt_small;
}
}
build(l,m,d + );
build(m + ,r,d + );
}
void Init()
{
memset(cnt,,sizeof(cnt));
sort(sor+,sor+n+);
build(,n,);
}
int query(int L,int R,int k,int l,int r,int d)//查询区间[L,R]中第K大的值
{
if(l == r){//找到
return num[d][l];
}
int m = (l + r) >> ;
int s, ss;//s表示[l,L)中小于sor[m]的个数 ss表示[L,R]中小于sor[m]的个数
if(l == L)s = ;//如果左边界相同 不能cnt[d][L-1] 因为L-1有可能是别的子树的
else s = cnt[d][L - ];
ss = cnt[d][R] - s;
if(ss >= k){//如果当前区间内左孩子的个数足够k个,那么就要进入左孩子查询
int newl = l + s;//左边会变成l + s 因为左孩子的值都小于sor[m] 建树的时候,数组的相对大小顺序没有改变,也就是说这是一个稳定的排序。
//也就是说从d到d+1时 加入的数 还是按照相对顺序的
//所以这里的新的左边界 就是l + s, 我们要找的d+1层中 左孩子都是小于sor[m]的!!
// s是[l,L)的到左孩子的值, 看) 所以不需要减一
int newr = l + s + ss - ;//同理 不过由于这里 s + ss后就是[l,R] 连起来了 所以需要减一
return query(newl,newr,k,l,m,d + );
}
else {
int a = L - l - s;//不需要加一 因为L这里不算 所以后面的newl需要加1
//a表示[l,L)之间大于sor[m]的个数 也就是要进入右孩子的个数
int b = R - L + - ss;//b表示[L,R]之间 进入右孩子的个数
int newl = m + + a;//右孩子的值都大于sor[m] 所以原来的左边界 在右孩子中会变成 m + 1 + a
int newr = m + a + b;//b是长度 由于m本需要+1 但是由于加了长度就已经+1了 其实是 m + 1 + a + b - 1
return query(newl,newr,k - ss,m + ,r,d + );
}
}
void solve(int q)
{
int x,y,k;
while(q--){
scanf("%d%d%d",&x,&y,&k);
printf("%d\n",query(x,y,k,,n,));
}
}
int main()
{
int q;
int t;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&q);
memset(num,,sizeof(num));
for(int i = ; i <= n; i++){
scanf("%d",&num[][i]);
sor[i] = num[][i];
}
Init();
solve(q);
}
return ;
}
hdu2665 && poj2104划分树的更多相关文章
- poj2104(划分树模板)
poj2104 题意 给出一个序列,每次查询一个区间,要求告诉这个区间排序后的第k个数. 分析 划分树模板,O(mlogn). 建树.根据排序之后的数组,对于一个区间,找到中点的数,将整个区间分为左右 ...
- poj2104 划分树 区间K大 在线 无修改
博主sbit....对于高级数据结构深感无力,然后这些东西在OI竟然烂大街了,不搞就整个人都不好了呢. 于是我勇猛的跳进了这个大坑 ——sbit 区间K大的裸题,在线,无修改. 可以用归并树(\(O( ...
- 初学划分树,小见解之!POJ-2104/HDU-2665
划分树 本来是学主席树的,可怜我等巨弱观群巨博客难解fotle主席的思想精髓.于是学了一下划分树,嗯,花了一下午时间理解build(其实自己模拟一遍就通了),我很难理解为什么划分树会看不懂而能学会主席 ...
- 划分树(poj2104)
poj2104 题意:给出n个数,有m次查询,每次查询要你找出 l 到 r 中第 k 大的数: 思路:划分树模板题 上述图片展现了查询时如何往下递推的过程 其中ly表示 [sl,l) 中有多少个数进入 ...
- poj2104(划分树模板)
poj2104 题意 给出一个序列,每次查询一个区间,要求告诉这个区间排序后的第k个数. 分析 划分树模板,O(mlogn). 建树.根据排序之后的数组,对于一个区间,找到中点的数,将整个区间分为左右 ...
- poj2104&&poj2761 (主席树&&划分树)主席树静态区间第k大模板
K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 43315 Accepted: 14296 Ca ...
- poj2104 线段树 划分树
学习:http://www.cnblogs.com/pony1993/archive/2012/07/17/2594544.html 划分树的build: 划分树是分层构建的,在构建的t层时,我们可以 ...
- POJ2104 k-th number 划分树
又是不带修改的区间第k大,这次用的是一个不同的方法,划分树,划分树感觉上是模拟了快速排序的过程,依照pivot不断地往下划分,然后每一层多存一个toleft[i]数组,就可以知道在这一层里从0到i里有 ...
- 划分树 poj2104 hdu5249
KPI Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submis ...
随机推荐
- POJ3621Sightseeing Cows[01分数规划 spfa(dfs)负环 ]
Sightseeing Cows Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 9703 Accepted: 3299 ...
- 利用注解进行sql反射代码示例
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Table { String val ...
- using关键字的使用
using语句的两个作用: 1)using可以导入命名空间 2)using可以释放对象占用的内存资源. 代码如下: using (SqlConnection con=new SqlConnection ...
- Flex4的可视化显示对象
flex3中用addChild(child:DisplayObject) 增加显示对象,flex4中用addElement(element:IVisualElement).绝大多数的flex3显示控件 ...
- java 22 - 5 多线程之获取和设置线程对象的名称
如何获取线程对象的名称呢? public final String getName():获取线程的名称.如何设置线程对象的名称呢? public final void setName(String n ...
- Eclipse c++代码提示,覆盖下面代码的问题。
今天在使用Eclipse自动提示时,会覆盖下面行的代码!!! 这个错误几乎不能忍,goolge无果. 手动尝试去掉,全部代码提示,终于找到解法办法,但是原因未知. 如下图:需要去掉 "Par ...
- 深入理解Linux修改hostname(转载)
http://www.cnblogs.com/kerrycode/p/3595724.html http://www.centoscn.com/CentOS/config/2014/1031/4039 ...
- JavaScript中的this关键字
在JavaScript中,函数的this关键字的行为与其他语言相比有很多不同.在JavaScript的严格模式和非严格模式下也略有区别. 在绝大多数情况下,函数的调用方式决定了this的值.this不 ...
- Visual Studio2012打开时弹出“遇到异常:这可能是由某个扩展导致的”错误的解决办法
Visual Studio2012打开时弹出"遇到异常:这可能是由某个扩展导致的"错误的解决办法: 具体问题如下: 分析原因:网上搜集了以下,出现异常的原因是安装了第三方控件,然后 ...
- Windows 8的本地化应用程序清单
I need to localize some data in application manifest (like name, description, splashscreen images et ...