【POJ】【2104】区间第K大
可持久化线段树
可持久化线段树是一种神奇的数据结构,它跟我们原来常用的线段树不同,它每次更新是不更改原来数据的,而是新开节点,维护它的历史版本,实现“可持久化”。(当然视情况也会有需要修改的时候)
可持久化线段树的应用有很多,仅以区间第K大这种简单的问题来介绍这种数据结构。
我们原本建立的线段树是表示区间的,或者说,维护的是【位置】,存的是每个位置上的各种信息。它的优点是满足区间加法,但不满足区间减法,所以我们这里要换一种建树方式:对于每个区间[1,i]建立一棵权值线段树。这个线段树的作用其实就跟前缀和差不多,且像前缀和一样满足区间减法!只不过我们在求前缀和的时候保留的是sum,而权值线段树把所有的值都存下来了。
这里说一下它的保存方式:对[1,x]这个节点,它需要维护一个cnt值,表示在[1,x]这个值域,有cnt个数。
举个栗子,我们现在有一个序列{1,2,3,4,5,2,3,3,3,3}
然后对于表示区间[1,10]的线段树,它的节点是这样建的

可以看出,值在[1,5]的有10个数,在[1,2]的有3个数……以此类推
那么我们在查询第K大的时候,就可以像平衡树那样!如果左儿子的cnt>=k则在左边找,否则在右边找,那么我们就可以顺利地查询到第K大了~
那么问题来了:如果我想查询[3,7]这个区间上第3大的数应该怎么办呢?(这个地方容易晕,一定要分清原序列的区间和值域,虽然都是用方括号的区间表示的……如果看了这句话更晕了,那就忘了它吧)
那么就要回到我们之前说的【前缀和】上来了,我们以前快速求[l,r]的区间和,是利用前缀和[1,l-1]和[1,r]区间相减快速计算的,同理,我们也可以利用[1,l-1]和[1,r]两棵线段树来进行区间第K大的查询。即在两棵树上同时往下走!详见代码。
//POJ 2104
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define rep(i,n) for(int i=0;i<n;++i)
#define F(i,j,n) for(int i=j;i<=n;++i)
#define D(i,j,n) for(int i=j;i>=n;--i)
using namespace std;
const int N=;
//#define debug struct node{
int x,num,rank;
}a[N];
bool cmpx(node a,node b){
return a.x<b.x;
}
bool cmpn(node a,node b){
return a.num<b.num;
} struct Tree{
int cnt,l,r;
}t[N*];
int root[N],cnt=,n,m; #define mid (l+r>>1)
void updata(int &o,int l,int r,int pos){
t[++cnt]=t[o], o=cnt, ++t[o].cnt;
if (l==r) return;
if (pos<=mid) updata(t[o].l,l,mid,pos);
else updata(t[o].r,mid+,r,pos);
#ifdef debug
printf("%d %d %d %d\n",o,l,r,pos);
#endif
} int query(int i,int j,int rank){
i=root[i],j=root[j];
int l=,r=n;
while(l!=r){
if (t[t[j].l].cnt-t[t[i].l].cnt>=rank)//在两棵树上一起往下走
r=mid,i=t[i].l,j=t[j].l;
else{
rank-=t[t[j].l].cnt-t[t[i].l].cnt;
l=mid+,i=t[i].r,j=t[j].r;
}
}
return l;
}
#undef mid int main(){
freopen("file.in","r",stdin);
scanf("%d%d",&n,&m);
int x=;
F(i,,n) {scanf("%d",&a[i].x); a[i].num=i;}
sort(a+,a+n+,cmpx);
F(i,,n) a[i].rank=i;
sort(a+,a+n+,cmpn);
F(i,,n) {
root[i]=root[i-];
updata(root[i],,n,a[i].rank);//此处可以先不理解……
//简单来说就是:为了节约空间,我们并不需要真的给每个区间建一棵完整的线段树
//而是可以在原来的基础上进行新的维护(即原来的为历史版本)
}
sort(a+,a+n+,cmpx);
F(i,,m){
int l,r,k;
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",a[query(l-,r,k)].x);
}
return ;
}
【POJ】【2104】区间第K大的更多相关文章
- POJ 2104 区间第k大(主席树)
题目链接:http://poj.org/problem?id=2104 题目大意:给定还有n个数的序列,m个操作,每个操作含有l,r,k,求区间[l,r]第k大 解题思路:线段树只能维护序列的最大值最 ...
- Poj 2104区间第k大(归并树)
题目链接 K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 36890 Accepted: 11860 C ...
- POJ 2104 K-th Number 主席树(区间第k大)
题目链接: http://poj.org/problem?id=2104 K-th Number Time Limit: 20000MSMemory Limit: 65536K 问题描述 You ar ...
- POJ 2104 静态找区间第k大
静态区间第k大的问题,往往可以利用主席树来解决 这是主席树的第一道题 主席树大概可以理解为在n个节点上都建立一棵线段树,但是想想会超出内存 每一个节点保存的线段树都记录当前整段前缀区间的信息 但是因为 ...
- poj 2104 主席树(区间第k大)
K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 44940 Accepted: 14946 Ca ...
- POJ 2104 && POJ 2761 (静态区间第k大,主席树)
查询区间第K大,而且没有修改. 使用划分树是可以做的. 作为主席树的入门题,感觉太神奇了,Orz /* *********************************************** ...
- POJ 2104 HDU 2665 主席树 解决区间第K大
两道题都是区间第K大询问,数据规模基本相同. 解决这种问题, 可以采用平方划分(块状表)复杂度也可以接受,但是实际表现比主席树差得多. 这里大致讲一下我对主席树的理解. 首先,如果对于某个区间[L,R ...
- 解决区间第K大的问题的各种方法
例题:http://poj.org/problem?id=2104 最近可能是念念不忘,必有回响吧,总是看到区间第k大的问题,第一次看到是在知乎上有人面试被弄懵了后来又多次在比赛中看到.以前大概是知道 ...
- 静态区间第k大(主席树)
POJ 2104为例(主席树入门题) 思想: 可持久化线段树,也叫作函数式线段树,也叫主席树(高大上). 可持久化数据结构(Persistent data structure):利用函数式编程的思想使 ...
随机推荐
- Vue.js学习 Item12 – 内部响应式原理探究
深入响应式原理 大部分的基础内容我们已经讲到了,现在讲点底层内容.Vue.js 最显著的一个功能是响应系统 —— 模型只是普通对象,修改它则更新视图.这让状态管理非常简单且直观,不过理解它的原理也很重 ...
- js验证表单大全
js验证表单大全 1. 长度限制 <script> function test() { if(document.a.b.value.length>50) { alert(" ...
- 【摘抄】Application.StartupPath和System.Environment.CurrentDirectory的区别
System.Environment.CurrentDirectory的含义是获取或设置当前工作路径,而Application.StartupPath是获取程序启动路径,表面上看二者没什么区别,但实际 ...
- Oracle 11gR2 RAC修改SCAN IP
一.查看当前环境: # grid用户 检查scan-ip地址的配置 [grid@node1 ~]$ srvctl config scan SCAN name: scan-cluster.com, Ne ...
- STM32F0xx_ADC采集电压配置详细过程
前言 关于ADC这一块的功能基本上也算是CortexM芯片的标配了.ST的每一块芯片都有这个功能,只是说因型号不同,通道数.位数等有所不同.STM8的芯片大多数都是10的,也就是说分辨率可达到:参考电 ...
- 第五章 管理程序流(In .net4.5) 之 异常处理
1. 概述 本章包括.net4.5中异常处理相关的部分. 2. 主要内容 2.1 处理异常 ① try.cahtch.finally 机制,无需多言. ② 使用 Environment.FailFas ...
- ASP.NET Core文章汇总
现有Asp.Net Core 文章资料,2016 3-20月汇总如下 ASP.NET Core 1.0 与 .NET Core 1.0 基础概述 http://www.cnblogs.com/Irvi ...
- L2-015. 互评成绩
学生互评作业的简单规则是这样定的:每个人的作业会被k个同学评审,得到k个成绩.系统需要去掉一个最高分和一个最低分,将剩下的分数取平均,就得到这个学生的最后成绩.本题就要求你编写这个互评系统的算分模块. ...
- 随机数范围扩展(如rand7()到rand10())(转)
题目:已知有个rand7()的函数,返回1到7随机自然数,让利用这个rand7()构造rand10() 随机1~10.分析:要保证rand10()在整数1-10的均匀分布,可以构造一个1-10*n的均 ...
- windows phone listbox虚拟化(下)
之前写过一篇关于listbox虚拟化的文章,那里采用的方法都是自己早期研究的一些思路,然后发现当数据很大的时候,其实性能效果还是不太理想,下面让我们来仔细想一想到底是基于什么原因,我们回去破坏默认的虚 ...