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 ...
随机推荐
- UIView转场动画属性设置
常规动画属性设置(可以同时选择多个进行设置) UIViewAnimationOptionLayoutSubviews:动画过程中保证子视图跟随运动. UIViewAnimationOptionAllo ...
- xcode 最近打开文件列表显示为空或不显示最近打开的项目或(no recent projects)解决办法
如果使用的是10.10 系统,打开系统设置-->进入通用-->在最下面的"最近使用的项目"中将0改为你可以接受的选项 如果不是10.10,那么就从系统偏好设置---&g ...
- mysql error笔记1
mysql视图问题: The user specified as a definer ('root'@'%') does not exist 原因:由于root用户对全局host无访问权限,给root ...
- (hdu)1285 确定比赛名次
Problem Description 有N个比赛队(<=N<=),编号依次为1,,,....,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接 ...
- C++类继承内存布局(三)
参考:http://blog.csdn.net/jiangyi711/article/details/4890889# (三)成员函数 类X中每一个非静态成员函数都会接受一个特殊的隐藏参数——this ...
- 为 DataGridView 控件添加行号
虽然好像不经常用到,不过还是记下来防止以后用到 /// <summary> /// 为 DataGridView 控件添加行号 /// </summary> /// <p ...
- window.onresize 多次触发的解决方法
用了window.onresize但是发现每次 onresize 后页面中状态总是不对,下面与大家分享下onresize 事件多次触发的解决方法. 之前做一个扩展,需要在改变窗口大小的时候保证页面显示 ...
- Linux调整SWAP分区
刪除原swap分區,重建swap,步驟如下:1,swapoff -a #停止交換分區2,fdisk /dev/sda #進入fdisk,刪除原swap分區,重新建立新分區(swap分區的系統ID是82 ...
- 【javascript 动态添加数据到 HTML 页面】
今天简单的学习了一下有关对象字面量的定义和 javascript 如何取出对象字面量的值的知识,javascript 动态添加数据到 HTML 页面的问题. [学习目标]有如下的一组数据通过 Ajax ...
- 用vld分析C++内存泄漏
最近发现项目里有内存泄漏,到网上搜了一些资料,决定用vld来分析解决这个问题. 直接在vs里的"工具和扩展"中搜索vld,然后下载安装就可以了. 我下载下来的是个exe文件,安装在 ...