Description

You are working for Macrohard company in data structures department. After failing your previous task about key insertion you were asked to write a new data structure that would be able to return quickly k-th order statistics in the array segment. 
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 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

For each question output the answer to it --- the k-th number in sorted a[i...j] segment.

题目大意:给一串数字,多次询问区间的第k小值

思路:不带修改的主席树

附资料:http://blog.csdn.net/metalseed/article/details/8045038

http://www.abandonzhang.com/archives/29

——————————————————————————————————————————————————————————————————————————————————————————————

以下转自http://prominences.weebly.com/1/post/2013/02/1.html

可持久化线段树,也叫作函数式线段树,也就是主席树,(。。。因为先驱就是fotile主席。。Orz。。。)
网上的教程很少啊,有的教程写得特别简单,4行中文,然后就是一篇代码~~
这里,我将从查找区间第k小值(不带修改)题的可持久化线段树做法中,讲一讲主席树。
/*只是略懂,若有错误,还请多多包涵!*/
可持久化数据结构(Persistent data structure)就是利用函数式编程的思想使其支持询问历史版本、同时充分利用它们之间的共同数据来减少时间和空间消耗。/*找不到比较科学的定义,就拿这个凑凑数吧~~~*/
这个数据结构很坑啊,我研究了一整天才差不多理解了一些(。。太笨了。。。)。所以,要理解好每一个域或变量的意义。
开讲!
一些数据结构,比如线段树或平衡树,他们一般是要么维护每个元素在原序列中的排列顺序,要么是维护每个元素的大小顺序,若是像二者兼得。。(反正我是觉得很。。)那么,这道题就想想主席树吧~/*还可以用划分树做*/
开讲!~好像说过一边了
既然叫“函数式线段树”,那么就应该有跟普通线段树相同的地方。一颗线段树,只能维护一段区间里的元素。但是,每个询问的区间都不一样,若是对每段区间都单独建立的线段树,那~萎定了~。因此,就要想,如何在少建,或建得快的情况下,能利用一些方法,得出某个区间里的情况。
比如一棵线段树,记为tree[i][j],表示区间[i,j]的线段树。那么,要得到它的情况,可以利用另外两棵树,tree[1][i-1]和tree[1][j],得出来。也就是说,可以由建树的一系列历史版本推出。
那么,怎么创建这些树呢?
首先,离散化数据。因为如果数据太大的话,线段树会爆~~
在所有树中,是按照当前区间元素的离散值(也就是用大小排序)储存的,在每个节点,存的是这个区间每个元素出现的次数之和(data域)。出现的次数,也就是存了多少数进来(建树时,是一个数一个数地存进来的)。
先建议棵线段树,所有的节点data域为0。再一个节点一个节点地添加。把每个数按照自己的离散值,放到树中合适的位置,然后data域+1,回溯的时候也要+1。当然,不能放到那棵空树中,要重新建树。第i棵树存的是区间(原序列)[1,i]。但是,如果是这样,那么会MLE+TLE。因此,要充分利用历史版本。用两个指针,分指当前空树和前一棵树。因为每棵树的结构是一样的,只是里面的data域不同,但是两棵相邻的树,只有一数只差,因此,如果元素要进左子树的话,右子树就会跟上个树这个区间的右子树是完全一样的,因此,可以直接将本树本节点的右子树指针接到上棵树当前节点的右儿子,这样即省时间,又省空间。
每添加一个节点(也就是新建一棵树)的复杂度是O(logn),因此,这一步的复杂度是O(nlogn)。
建完之后,要怎么查找呢?
跟一般的,在整棵树中找第k个数是一样的。如果一个节点的左权值(左子树上点的数量之和)大于k,那么就到左子树查找,否则到右子树查找。其实主席树是一样的。对于任意两棵树(分别存区间[1,i]和区间[1,j] i<j),在同一节点上(两节点所表示的区间相同),data域之差表示的是,原序列区间[i,j]在当前节点所表示的区间里,出现多少次(有多少数的大小是在这个区间里的)。同理,对于同一节点,如果在两棵树中,它们的左权值之差大于等于k,那么要求的数就在左孩子,否则在右孩子。当定位到叶子节点时,就可以输出了。

——————————————————————————————————————————————————————————————————————————————————————————————

鄙人的一些理解:所谓主席树呢,就是对原来的数列[1..n]的每一个前缀[1..i](1≤i≤n)建立一棵线段树,线段树的每一个节点存某个前缀[1..i]中属于区间[L..R]的数一共有多少个(比如根节点是[1..n],一共i个数,sum[root] = i;根节点的左儿子是[1..(L+R)/2],若不大于(L+R)/2的数有x个,那么sum[root.left] = x)。若要查找[i..j]中第k大数时,设某结点x,那么x.sum[j] - x.sum[i - 1]就是[i..j]中在结点x内的数字总数。而对每一个前缀都建一棵树,会MLE,观察到每个[1..i]和[1..i-1]只有一条路是不一样的,那么其他的结点只要用回前一棵树的结点即可,时空复杂度为O(nlogn)。

代码(最原始的树所有结点的值都为0,就算建好一棵树了……):

 #include <cstdio>
#include <algorithm>
using namespace std; const int MAXN = ; struct Node {
int L, R, sum;
};
Node T[MAXN * ];
int T_cnt; void insert(int &num, int &x, int L, int R) {
T[T_cnt++] = T[x]; x = T_cnt - ;
++T[x].sum;
if(L == R) return ;
int mid = (L + R) >> ;
if(num <= mid) insert(num, T[x].L, L, mid);
else insert(num, T[x].R, mid + , R);
} int query(int i, int j, int k, int L, int R) {
if(L == R) return L;
int t = T[T[j].L].sum - T[T[i].L].sum;
int mid = (R + L) >> ;
if(k <= t) return query(T[i].L, T[j].L, k, L, mid);
else return query(T[i].R, T[j].R, k - t, mid + , R);
} struct A {
int x, idx;
bool operator < (const A &rhs) const {
return x < rhs.x;
}
}; A a[MAXN];
int rank[MAXN], root[MAXN];
int n, m; int main() {
T[].L = T[].R = T[].sum = ;
root[] = ;
while(scanf("%d%d", &n, &m) != EOF) {
for(int i = ; i <= n; ++i) {
scanf("%d", &a[i].x);
a[i].idx = i;
}
sort(a + , a + n + );
for(int i = ; i <= n; ++i) rank[a[i].idx] = i;
T_cnt = ;
for(int i = ; i <= n; ++i) {
root[i] = root[i - ];
insert(rank[i], root[i], , n);
}
while(m--) {
int i, j, k;
scanf("%d%d%d", &i, &j, &k);
printf("%d\n", a[query(root[i - ], root[j], k, , n)].x);
}
}
}

POJ 2104 K-th Number(主席树——附讲解)的更多相关文章

  1. 【POJ 2104】 K-th Number 主席树模板题

    达神主席树讲解传送门:http://blog.csdn.net/dad3zz/article/details/50638026 2016-02-23:真的是模板题诶,主席树模板水过.今天新校网不好,没 ...

  2. poj2104 k-th number 主席树入门讲解

    poj2104 k-th number 主席树入门讲解 定义:主席树是一种可持久化的线段树 又叫函数式线段树   刚开始学是不是觉得很蒙逼啊 其实我也是 主席树说简单了 就是 保留你每一步操作完成之后 ...

  3. 静态区间第k大(主席树)

    POJ 2104为例(主席树入门题) 思想: 可持久化线段树,也叫作函数式线段树,也叫主席树(高大上). 可持久化数据结构(Persistent data structure):利用函数式编程的思想使 ...

  4. poj 2104 K-th Number 主席树+超级详细解释

    poj 2104 K-th Number 主席树+超级详细解释 传送门:K-th Number 题目大意:给出一段数列,让你求[L,R]区间内第几大的数字! 在这里先介绍一下主席树! 如果想了解什么是 ...

  5. POJ 2104 K-th Number 主席树(区间第k大)

    题目链接: http://poj.org/problem?id=2104 K-th Number Time Limit: 20000MSMemory Limit: 65536K 问题描述 You ar ...

  6. POJ 2104:K-th Number(主席树静态区间k大)

    题目大意:对于一个序列,每次询问区间[l,r]的第k大树. 分析: 主席树模板题 program kthtree; type point=record l,r,s:longint; end; var ...

  7. POJ 2104 K-th Number ( 求取区间 K 大值 || 主席树 || 离线线段树)

    题意 : 给出一个含有 N 个数的序列,然后有 M 次问询,每次问询包含 ( L, R, K ) 要求你给出 L 到 R 这个区间的第 K 大是几 分析 : 求取区间 K 大值是个经典的问题,可以使用 ...

  8. SPOJ MKTHNUM & POJ 2104 - K-th Number - [主席树模板题]

    题目链接:http://poj.org/problem?id=2104 Description You are working for Macrohard company in data struct ...

  9. poj 2104 K-th Number(主席树 视频)

    K-th Number 题意: 给你一些数,让你求一个区间内,第k大的数是多少. 题解: 主席树第一题,看的qsc视频写的,戳戳戳 学到了unique函数,他的作用是:把相邻的重复的放到后面,返回值是 ...

随机推荐

  1. FLEX SharedObject介绍及应用

    ShareObject介绍: 1 ShareObject,顾名思义共享对象,而通常意义上的共享,从B/S结构上来讲,无非是客户端(浏览器端)的共享和服务器端的共享了,不错,ShareObject刚好份 ...

  2. java编程eclipse常用快捷键方式

    Eclipse 常用快捷键 Eclipse的编辑功能非常强大,掌握了Eclipse快捷键功能,能够大大提高开发效率.Eclipse中有如下一些和编辑相关的快捷键. 1. [ALT+/] 此快捷键为用户 ...

  3. REST

    REST (REpresentational State Transfer). 为REST模式的Web服务与复杂的SOAP和XML-RPC对比来讲明显的更加简洁. "设计良好的网络应用表现为 ...

  4. TFS任务更新

    由于不熟悉TFS任务更新的操作,花了四五个小时一个个的新建任务.下图是部分更新的任务截图: 每个任务的估计时间为3~5小时,每位成员的任务总时长均为19~20小时. 项目完成需要的总时间为135小时.

  5. webform连接ACCESS数据库

    1.先建立一个名叫mydb.accdb的access数据库 2.他它复制到webform中,放在App_Data文件夹下. 3.在App_Code文件夹下建好封装语句,查询方法,连接语句,其中stud ...

  6. 织梦5.7 TAG、标题、栏目以及keywords长度字符数限制修改

    织梦5.7 TAG.标题.栏目以及keywords长度字符数限制修改[图文]   标签: 织梦关键词长度修改 织梦tag长度修改 织梦标题长度修改 织梦栏目长度限制修改 织梦修改 分类: 技术操作   ...

  7. 关于web-dev-server 记录

    package.json "scripts": { "init": "webpack --progress --config webpack.dev. ...

  8. IOS第12天(2,UINavigationController导航控制器)

    ****HMAppDelegate.m @implementation HMAppDelegate - (BOOL)application:(UIApplication *)application d ...

  9. 网页FLASH幻灯片播放带链接源代码 pixviewer.swf使用(转)

        <script type="text/javascript"> <!-- var focus_width=360 var focus_height=270 ...

  10. rbd命令

    chen@admin-node:~$ rbd --help usage: rbd [-n <auth user>] [OPTIONS] <cmd> ... where 'poo ...