K-th Number
Time Limit: 20000MS   Memory Limit: 65536K
Total Submissions: 51440   Accepted: 17594
Case Time Limit: 2000MS

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. 

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

Hint

This problem has huge input,so please use c-style input(scanf,printf),or you may got time limit exceed.

Source

Northeastern Europe 2004, Northern Subregion

document:

1.http://blog.csdn.net/metalseed/article/details/8045038

2.http://www.cnblogs.com/oyking/p/3230296.html

 
解决区间极值查询问题
主席树就是对每个前缀做了一个线段树
这样相当于处理了前缀和
提取一段区间,就是T[j]-T[i-1]
每棵线段树都按照[1,n]建树(保证链可以共用)
离散化后按照序列的顺序建树
T[i+1]和T[i]只有一条链不同,其他的可以共用
 
插入操作就是只把新链上的节点新建,其他的都用上一课树的
查询操作就是一个kth的过程,只不过要用两棵树的差值
 
PS:
1.两种建树写法,貌似用引用比较快
2.每个数字不同,离散化排序就行了
 
[2016-12-31]一些新理解
就是可持久化线段树,对于每个版本建立一颗线段树,可以查询历史版本
为了节省内存和时间直接使用历史版本的形态,把修改的地方沿途新开节点,其他地方继承历史版本
主席树就是前缀和套线段树,每个前缀和建立一颗线段树,继承上一个历史版本,只是单点修改
区间修改也一样,所有区间修改到的点都要新开节点 标记下放时也要新开
总结:就是把各种操作修改到(包括因为下方标记而修改)的节点新开节点,写法上就是多了新开节点而已,其他一样
主席树的线段树是值域线段树,线段树的形态固定并且维护的信息是出现次数所以是可减的,那么主席树做差就得到了一个区间的值域线段树,可以在线段树上二分求kth
 
主席树的空间实际<理论

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1e5+;
int read(){
char c=getchar();int x=,f=;
while(c<''||c>''){if(c=='-')f=-; c=getchar();}
while(c>=''&&c<=''){x=x*+c-''; c=getchar();}
return x*f;
}
int n,m,mp[N],l,r,k;
struct data{
int v,id;
bool operator <(const data &r)const{return v<r.v;}
}a[N];
struct node{
int lc,rc,size;
}t[N*];
int cnt=,root[N];
void insert(int num,int &x,int l,int r){//printf("ins %d %d %d\n",l,r,x);
cnt++;
t[cnt]=t[x];x=cnt;
++t[x].size;
if(l==r) return;
int mid=(l+r)>>;
if(num<=mid) insert(num,t[x].lc,l,mid);
else insert(num,t[x].rc,mid+,r);
}
int ins(int num,int pre,int l,int r){
int x=++cnt;
t[x]=t[pre]; ++t[x].size;
if(l==r) return x;
int mid=(l+r)>>;
if(num<=mid) t[x].lc=ins(num,t[x].lc,l,mid);
else t[x].rc=ins(num,t[x].rc,mid+,r);
return x;
}
int query(int i,int j,int l,int r,int k){
if(l==r) return l;
int ls=t[t[j].lc].size-t[t[i].lc].size;
int mid=(l+r)>>;
if(k<=ls) return query(t[i].lc,t[j].lc,l,mid,k);
else return query(t[i].rc,t[j].rc,mid+,r,k-ls);
} int main(){
n=read();m=read();
for(int i=;i<=n;i++) a[i].v=read(),a[i].id=i;
sort(a+,a++n);
for(int i=;i<=n;i++) mp[a[i].id]=i; for(int i=;i<=n;i++){
//root[i]=ins(mp[i],root[i-1],1,n);
root[i]=root[i-];
insert(mp[i],root[i],,n);
}
while(m--){
l=read();r=read();k=read();
printf("%d\n",a[query(root[l-],root[r],,n,k)].v); }
}

[2017-03-02]

在扔上一点课件上的东西,虽然感觉跟前面的总结有点重复,但还是有点用吧

函数式编程:不修改,只新增(保留所有的历史版本)。
@ 考虑一次单点修改对整棵树的信息的影响;只有一条链上的
信息真正改变了。
@ 函数式线段树:对于线段树所有的单点修改操作,不真正的
修改,而是通过新增节点的方式来构建。

由于除了链上的信息是不变的,所以把直接指向它们就可以
了。
@ 所以整棵线段树是动态的,要用动态的节点来实现。
@ 只需要记录根节点,就能访问“第x 次修改后的线段树”
了。

新模板:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define lc(x) t[x].lc
#define rc(x) t[x].rc
typedef long long ll;
const int N=1e5+;
int read(){
char c=getchar();int x=,f=;
while(c<''||c>''){if(c=='-')f=-; c=getchar();}
while(c>=''&&c<=''){x=x*+c-''; c=getchar();}
return x*f;
}
int n,m,mp[N],l,r,k;
struct Fode{
int v,id;
bool operator <(const data &r)const{return v<r.v;}
}a[N];
struct node{
int lc,rc,size;
}t[N*];
int sz,root[N];
void fIns(int &x,int l,int r,int p){
t[++sz]=t[x];x=sz;
t[x].size++;
if(l==r) return;
int mid=(l+r)>>;
if(p<=mid) fIns(t[x].lc,l,mid,p);
else fIns(t[x].rc,mid+,r,p);
}
int fQue(int x,int y,int l,int r,int k){
if(l==r) return l;
int lsize=t[lc(y)].size-t[lc(x)].size;
int mid=(l+r)>>;
if(k<=lsize) return fQue(lc(x),lc(y),l,mid,k);
else return fQue(rc(x),rc(y),mid+,r,k-lsize);
} int main(){
freopen("in","r",stdin);
n=read();m=read();
for(int i=;i<=n;i++) a[i].v=read(),a[i].id=i;
sort(a+,a++n);
for(int i=;i<=n;i++) mp[a[i].id]=i; for(int i=;i<=n;i++) root[i]=root[i-],fIns(root[i],,n,mp[i]);
while(m--){
l=read();r=read();k=read();
printf("%d\n",a[fQue(root[l-],root[r],,n,k)].v);
}
}
 
 

POJ2104 K-th Number[主席树]【学习笔记】的更多相关文章

  1. 主席树学习笔记(静态区间第k大)

    题目背景 这是个非常经典的主席树入门题——静态区间第K小 数据已经过加强,请使用主席树.同时请注意常数优化 题目描述 如题,给定N个整数构成的序列,将对于指定的闭区间查询其区间内的第K小值. 输入输出 ...

  2. 主席树学习笔记-hdu-2665

    主席树就是对每个历史版本都建了一颗线段树,这样我们在统计一些问题的时候,对于一个区间[L,R]的询问,就可以利用前缀和的思想找到第L-1和第R颗历史版本的线段树来处理查找.由于这样空间需求就增大了,注 ...

  3. 【poj2104】K-th Number 主席树

    题目描述 You are working for Macrohard company in data structures department. After failing your previou ...

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

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

  5. zkw线段树学习笔记

    zkw线段树学习笔记 今天模拟赛线段树被卡常了,由于我自带常数 \(buff\),所以学了下zkw线段树. 平常的线段树无论是修改还是查询,都是从根开始递归找到区间的,而zkw线段树直接从叶子结点开始 ...

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

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

  7. 仙人掌&圆方树学习笔记

    仙人掌&圆方树学习笔记 1.仙人掌 圆方树用来干啥? --处理仙人掌的问题. 仙人掌是啥? (图片来自于\(BZOJ1023\)) --也就是任意一条边只会出现在一个环里面. 当然,如果你的图 ...

  8. 线段树学习笔记(基础&进阶)(一) | P3372 【模板】线段树 1 题解

    什么是线段树 线段树是一棵二叉树,每个结点存储需维护的信息,一般用于处理区间最值.区间和等问题. 线段树的用处 对编号连续的一些点进行修改或者统计操作,修改和统计的复杂度都是 O(log n). 基础 ...

  9. [POJ2104] K – th Number (可持久化线段树 主席树)

    题目背景 这是个非常经典的主席树入门题--静态区间第K小 数据已经过加强,请使用主席树.同时请注意常数优化 题目描述 如题,给定N个正整数构成的序列,将对于指定的闭区间查询其区间内的第K小值. 输入输 ...

随机推荐

  1. C#截屏

    本实例代码实现了WinForm截屏保存为图片,亲测可行. 界面截图: 下载:http://hovertree.com/h/bjaf/scjyuanma.htm 以下代码可以实际运行,在项目HoverT ...

  2. java程序员保持天天快乐的6个习惯

    忍不住感叹,我第一次对Buffer(在社交媒体上发布最简单的方式)有所想法已经差不多是两年前的事了.并且,在我有想法的一年半前,我还在前面那家新创公司工作的时...... 忍不住感叹,我第一次对Buf ...

  3. iOS--使用UIImageView进行GIF动图播放

    大家好,好久没有跟新了.其实也就昨天到今天的时间. 前言:实际上,GIF动图文件中包含了一组图片及其信息数组,这些信息数据记录着这一组图片中各张图片的播放时长等信息,我们可以将图片和这些信息或取出来, ...

  4. android.view.InflateException: Binary XML file line #34: Error inflating class

    问题一般出在xml的第三方View的全类名,你可能是直接粘贴过来的,没有改成自己项目的全类名.

  5. Linux(Centos)之安装Java JDK及注意事项

    1.准备工作 a.因为Java JDK区分32位和64位系统,所以在安装之前必须先要判断以下我们的Centos系统为多少位系统,命令如下: uname -a 解释:如果有x86_64就是64位的,没有 ...

  6. 从CSS实现正片叠底看=>混合模式mix-blend-mode

    兼容性:这个东西说多了也没意思,像HTML5和CSS3这种兼容性时刻变化的东东,我们最好在自己支持的设备上实验,不支持,就在想办法呗,这个东西就是为了方便和好玩 所有属性: mix-blend-mod ...

  7. 纯CSS3实现3D跳动小球

    请使用Chrome,火狐的浏览器查看本页面,使用IE将看不到效果.如果在本页看不到一个跳动的小球,请确定您的浏览器支持CSS3,或者访问http://keleyi.com/a/bjac/iphgrtq ...

  8. 简要分析webpack打包后代码

    开门见山 1.打包单一模块 webpack.config.js module.exports = { entry:"./chunk1.js", output: { path: __ ...

  9. Javascript中构造函数与new命令

    典型的面向对象编程语言(比如C++和Java),存在“类”(class)这个概念.所谓“类”就是对象的模板,对象就是“类”的实例.但是,在JavaScript语言的对象体系,不是基于“类”的,而是基于 ...

  10. express实现前后端通信上传图片,存储数据库(mysql)傻瓜教程(三)完结篇

    终于完成了所有自己想要的功能(鼓励下自己),虽然还是很简陋,但是还是挺有满足感的,哈哈. 附上前两篇的链接: 第一篇 第二篇 进入正题,在第二篇里面已经完成了连接数据库,并且实现了对数据库的增删改查, ...