POJ_2104_Kth_(主席树)
描述
http://poj.org/problem?id=2104
给出一个n个数的数列,m次询问,每次询问求区间[l,r]中第k小的数,无修改操作.
Time Limit: 20000MS | Memory Limit: 65536K | |
Total Submissions: 46951 | Accepted: 15697 | |
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
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
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
Source
分析
静态的主席树裸题.
首先考虑把数据离散化,这样一共有n个数,分别为1,2,...,n-1,n(如果没有重复的话)(如果题目里面说有重复且重复数字排名相同,就去一下重就好了).用N=n的线段树来表示某一区间当前的情况,其中节点a[k]表示在这个区间内,属于[a[k].L,a[k].R]的数字共有多少.这样在这个区间上求第K小数的操作就类似于平衡树上的操作,走到一个节点,如果左孩子的数字个数a[a[k].l].s>=k,那么第K大的数就在左孩子区间,否则就在右孩子区间.这样一棵线段树可以表示数列中的一个区间.那要求任意区间的,每一个区间都要有自己的线段树吗?不必.类似求任意区间的和值,可以利用前缀和的思想,每一棵线段树代表数列从第一个数到第i个数的区间,这样只需要n棵线段树即可.而每一棵线段树的形状,大小,含义都是一样的,所以在数列区间[l,r]中属于[a[k].L,a[k].R]的数的个数就是在数列区间[1,r]中的个数减去在数列区间[1,l-1]中的个数,所以用两棵前缀和线段树相减就可以得到在数列区间[l,r]中的个数.
以上就是解决问题的基本思路.
但是n棵线段树就需要n^2级别的空间,会MLE,解决这个问题的就是主席树(可持久化线段树).(其实我不太懂这个名字的含义)
对于表示数列区间[1,i]的线段树,它相对于表示数列区间[1,i-1]的线段树来说,多了一个数字A[i],那就是在A[i]的节点上s值要+1,并且要向上更新,所有包含A[i]的节点都要更新,这样更新的就是从上到下一整条链,而其他的点并没有变,所以没次只用更新logn个点(第一次也是).所以n次建树共需要nlogn个点,空间就够用了(开空间之前动手算一下log).
p.s.
1.我的写法是在进入某一节点之前就修改它相关的值,也可以在函数的参数里使用引用,进入某一节点之后再修改,更简洁,但初学还是如下写法比较好理解.
2.学习了新的离散化写法,也可以用一个结构体把id数组和a数组放在一起,效果是一样的,但这样写更简洁.预处理的复杂度是O(n)的,当然如果有重复的话写成结构体好去重.当然也可以直接排序去重,之后再用O(nlogn)的时间二分查找一遍,这样就不需要id数组了.
#include <cstdio>
#include <algorithm>
using namespace std; const int maxn=+;
int n,m,cnt;
int a[maxn],b[maxn],id[maxn],root[maxn];
struct node{ int l,r,x; }t[maxn*];
void update(int l,int r,int now,int pre,int x){
if(l==r) return;
int mid=l+(r-l)/;
if(x<=mid){
t[now].l=++cnt;
t[now].r=t[pre].r;
t[t[now].l].x=t[t[pre].l].x+;
update(l,mid,t[now].l,t[pre].l,x);
}
else{
t[now].l=t[pre].l;
t[now].r=++cnt;
t[t[now].r].x=t[t[pre].r].x+;
update(mid+,r,t[now].r,t[pre].r,x);
}
}
int query(int l,int r,int x,int y,int k){
if(l==r) return l;
int mid=l+(r-l)/;
int s=t[t[y].l].x-t[t[x].l].x;
if(k<=s) return query(l,mid,t[x].l,t[y].l,k);
else return query(mid+,r,t[x].r,t[y].r,k-s);
}
bool cmp(int x,int y){ return a[x]<a[y]; }
int main(){
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++) scanf("%d",&a[i]), id[i]=i;
sort(id+,id+n+,cmp);
for(int i=;i<=n;i++) b[id[i]]=i;
for(int i=;i<=n;i++){
root[i]=++cnt;
update(,n,cnt,root[i-],b[i]);
}
while(m--){
int x,y,k;
scanf("%d%d%d",&x,&y,&k);
printf("%d\n",a[id[query(,n,root[x-],root[y],k)]]);
}
return ;
}
p.s.
1.突然想起来第二种用到二分的离散化方法当初是自己想出来的...虽然不是很好用,但NOIP以前学习和练习的时候一直用的是自己想的东西,lca的最朴素算法也是自己想的,后来发现和书上写得一模一样.现在离thusc和NOI近了,一直在想抓紧时间多学一点,这样的想法是没错的,要抓紧时间,不能太懒散,但是有时候未免太过功利,其实自己是明白自己基本没什么希望的,但是这毕竟是自己热爱的和想要做的事.就算最后什么奖都没有,一次次地打酱油又怎样呢?自己的实力确实差得很远,有梦想是对的,但不该太功利,我应该为自己能够继续追逐梦想而感到幸运.一直以来都不应该那样浮躁,静不下心来.我应该抓紧时间去享受自己的OI,用心去做自己想要做的事,趁自己还有机会.所以很重要的:不能放弃思考.
POJ_2104_Kth_(主席树)的更多相关文章
- bzoj3207--Hash+主席树
题目大意: 给定一个n个数的序列和m个询问(n,m<=100000)和k,每个询问包含k+2个数字:l,r,b[1],b[2]...b[k],要求输出b[1]~b[k]在[l,r]中是否出现. ...
- bzoj1901--树状数组套主席树
树状数组套主席树模板题... 题目大意: 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]--a[ ...
- BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2050 Solved: 817[Submit][Status ...
- BZOJ 1146: [CTSC2008]网络管理Network [树上带修改主席树]
1146: [CTSC2008]网络管理Network Time Limit: 50 Sec Memory Limit: 162 MBSubmit: 3522 Solved: 1041[Submi ...
- BZOJ 2588: Spoj 10628. Count on a tree [树上主席树]
2588: Spoj 10628. Count on a tree Time Limit: 12 Sec Memory Limit: 128 MBSubmit: 5217 Solved: 1233 ...
- BZOJ 1901: Zju2112 Dynamic Rankings[带修改的主席树]【学习笔记】
1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 7143 Solved: 2968[Su ...
- [bzoj3932][CQOI2015][任务查询系统] (主席树)
Description 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si ...
- [bzoj2588][count on a tree] (主席树+lca)
Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始 ...
- [bzoj2653][middle] (二分 + 主席树)
Description 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序列s. 回答Q个这样的询问:s的左端点在[a,b ...
随机推荐
- 将Excel,ppt和word转化为html
有些时候可能需要将Excel,ppt和word转化为html在页面上显示.我从网上查到一些代码,记录在这里以供需要的朋友参考 1.将word转化为html显示 //================== ...
- dumpbin工具的使用
当我们需要查看一个dll或exe文件中的包含的函数或是依赖的函数之类的信息,可以使用Visual Studio自带的工具dumpbin来实现,使用方法为: 1/ 启动Visual Studio 命令行 ...
- Java根据出生年月日获取到当前日期的年月日
源码链接:http://pan.baidu.com/s/1sj61IUD
- Java并发编程:进程和线程之由来__进程让操作系统的并发性成为可能,而线程让进程的内部并发成为可能
转载自海子:http://www.cnblogs.com/dolphin0520/p/3910667.html Java多线程基础:进程和线程之由来 在前面,已经介绍了Java的基础知识,现在我们来讨 ...
- _itoa_s, _i64toa_s, _ui64toa_s, _itow_s, _i64tow_s, _ui64tow_s
Converts an integer to a string. These are versions of _itoa, _i64toa, _ui64toa, _itow, _i64tow, _ui ...
- 【BZOJ2793】【数学】[Poi2012]Vouchers
Description 考虑正整数集合,现在有n组人依次来取数,假设第i组来了x人,他们每个取的数一定是x的倍数,并且是还剩下的最小的x个. 正整数中有m个数被标成了幸运数,问有哪些人取到了幸运数. ...
- 利用Xlinix SDK 建立Linux程序以及对该程序进行调试
一.创建Linux程序 1. 点击File > New > Application Project .并参照下图设置. 2. 输入工程名,并选择存储路径. 3. 选择所需的操作系统平台(O ...
- nginx 502
查过网上的资源,基本都是认为是php线程打开文件句柄受限导致的错误.具体的解决的办法如下: 1.提升服务器的文件句柄打开打开 /etc/security/limits.conf : (增加) * ...
- centos 6.5 安装jenkins
Installation sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.rep ...
- jsonp 使用示例
客户端: <!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml"><head>< ...