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 ...
随机推荐
- 使用C#向ACCESS中插入数据
使用C#向ACCESS中插入数据 1.创建并打开一个OleDbConnection对象 string strConn = " Provider = Microsoft.Jet.OLEDB ...
- wamp5设置外网访问方法
1.安装完Wamp5之后,从外网访问网页时存在无法访问问题. 2.phpmyadmin外网没法访问 1.解决办法: 打开wamp的托盘图标(右下角),找到"Config files" ...
- 转:Configure your eclipse for C++
from: http://omtlab.com/configure-your-eclipse-for-c/ Configure your eclipse for C++ July 7, 2013 Th ...
- 理解android.intent.action.MAIN 与 android.intent.category.LAUNCHER
刚才看了一下sundy的视频<LLY110426_Android应用程序启动>,里面讲到luncher这个activity通过获取应用程序信息来加载应用程序,显示给用户,其中就是通过一个应 ...
- maya 专家模式
maya中按ctrl + 空格 可以在普通模式与专家模式之间切换,如图 普通模式 按ctrl+空格后进入专家模式 来自为知笔记(Wiz)
- Nginx针对https站点的部署
一.Nginx安装(略)安装的时候需要注意加上 --with-http_ssl_module,因为http_ssl_module不属于Nginx的基本模块.Nginx安装方法:# ./configur ...
- Linux 网络编程详解四(流协议与粘包)
TCP/IP协议是一种流协议,流协议是字节流,只有开始和结束,包与包之间没有边界,所以容易产生粘包,但是不会丢包. UDP/IP协议是数据报,有边界,不存在粘包,但是可能丢包. 产生粘包问题的原因 . ...
- codevs1842 递归第一次
难度等级:白银 1842 递归第一次 题目描述 Description 同学们在做题时常遇到这种函数 f(x)=5 (x>=0) f(x)=f(x+1)+f(x+2)+1 (x<0) 下面 ...
- checkbox页面全选
http://pan.baidu.com/s/1tfzSa
- QTableView 添加按钮
这里说一下怎么在QTableView添加一个按钮 添加两个按钮的例子在这篇文章里:QTableView 一列添加两个按钮 效果是点击button弹出一个对话框. 看一下ButtonDelegate的代 ...