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. 异构SOA系统架构之Asp.net实现(兼容dubbo)

    我们公司技术部门情况比较复杂,分到多个集团,每个集团又可能分为几个部门,每个部门又可能分为多个小组,组织架构比较复杂,开发人员比较多. 使用的编程语言也有点复杂,主流语言有.net(C#).Java. ...

  2. jquery定时滑出可最小化的底部提示层

    效果预览:http://keleyi.com/keleyi/phtml/jqtexiao/index.htm当打开页面或者刷新页面后等待两秒钟,会在底部滑出可最小化的提示层.滑出层半透明,可关闭再现. ...

  3. web前端交互性易用性说明

    总结一下我们在web前端开发过程中总是强调交互性.易用性的情况分析说明.个人觉得web前端的易用交互也就是我们所说人性化操作.不外乎希望达到的效果为:界面风格简洁明了.重点突出:操作简单,直观可见.当 ...

  4. javascript 函数初探 (二)--- 那些年的预定义函数

    javascript的预定义函数: javascript引擎中有一组可以随时调用的内建函数. 这些内建函数包括: 1. parseInt() 2. parseFloat() 3. isNaN() 4. ...

  5. Ionic + Cordova 跨平台移动开发环境配置

    1.下载安装JDK(根据各自系统选择32位或64位下载),安装完成之后需要做以下环境变量配置 在“系统变量”中,设置3象属性,JAVA_HOME,PATH,CLASSPATH(大小写无所谓),如果已经 ...

  6. jQuery属性/CSS使用例子

    jQuery属性/CSS 1..attr() 获取匹配的元素集合中的第一个元素的属性的值  或 设置每一个匹配元素的一个或多个属性. 例1:获取元素的属性的值 <p title="段落 ...

  7. jQuery插件之——简单日历

    最近在研究js插件的开发,以前看大神们,对插件都是信手拈来,随便玩弄,感觉自己要是达到那种水平就好了,就开始自己研究插件开发了.研究了一段时间之后,就开始写了自己的第一个日历插件,由于是初学插件开发, ...

  8. arcgis地图数据集合

    一.全国的ArcGIS地图SHP格式数据,覆盖的图层信息量基本齐全,除了ArcGIS之外,其他GIS软件(superMap和MapGIS.MapInfo等等)也是用之,适合为GIS开发提供数据素材. ...

  9. 另类的SQL注入方法

    前言:相比基于查询的SQL注入,使用insert.update和delete进行SQL注入显得略显另类 参考自:http://www.exploit-db.com/wp-content/themes/ ...

  10. sharepoint 提升权限报错

    现象: sharepoint中提升权限是为了模拟管理员操作,但是对于普通用户对item的更新和删除照成错误 解决办法: 去掉权限升级 说明: 升级权限能不用尽量不用,同时也不好排查权限问题.