描述


http://poj.org/problem?id=2104

给出一个n个数的数列,m次询问,每次询问求区间[l,r]中第k小的数,无修改操作.

K-th Number
Time Limit: 20000MS   Memory Limit: 65536K
Total Submissions: 46951   Accepted: 15697
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

分析


静态的主席树裸题.

首先考虑把数据离散化,这样一共有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_(主席树)的更多相关文章

  1. bzoj3207--Hash+主席树

    题目大意: 给定一个n个数的序列和m个询问(n,m<=100000)和k,每个询问包含k+2个数字:l,r,b[1],b[2]...b[k],要求输出b[1]~b[k]在[l,r]中是否出现. ...

  2. bzoj1901--树状数组套主席树

    树状数组套主席树模板题... 题目大意: 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]--a[ ...

  3. BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]

    3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2050  Solved: 817[Submit][Status ...

  4. BZOJ 1146: [CTSC2008]网络管理Network [树上带修改主席树]

    1146: [CTSC2008]网络管理Network Time Limit: 50 Sec  Memory Limit: 162 MBSubmit: 3522  Solved: 1041[Submi ...

  5. 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 ...

  6. BZOJ 1901: Zju2112 Dynamic Rankings[带修改的主席树]【学习笔记】

    1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 7143  Solved: 2968[Su ...

  7. [bzoj3932][CQOI2015][任务查询系统] (主席树)

    Description 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si ...

  8. [bzoj2588][count on a tree] (主席树+lca)

    Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始 ...

  9. [bzoj2653][middle] (二分 + 主席树)

    Description 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序列s. 回答Q个这样的询问:s的左端点在[a,b ...

随机推荐

  1. 归并排序算法(C#实现)

    归并排序(Merge Sort)是利用"归并"技术来进行排序.归并是指将若干个已排序的子文件合并成一个有序的文件.归并排序有两种方式:1): 自底向上的方法 2):自顶向下的方法 ...

  2. CAS Server 单点登录开源项目

    https://www.apereo.org/cas/download This project contains code that can extent an existing ASP.NET w ...

  3. iOS-开发日志-UIPageControl

    UIPageControl 1.  numberOfPages // 设置有多少页 默认为0 // 2) 设置页数 [pageControl setNumberOfPages:kImageCount] ...

  4. swift之元组类型

    一.元组类型是有N个任意类型的数据组成(N>=0),组成元组类型的数据可以称为“元素” 二.元组的定义 如:let position = (x:10.5,y:20)    //两个元素的元组 l ...

  5. javascript 基础1第11节

    <html> <head> <title>javascript基础</title> </head> <body> 1.NaN i ...

  6. JNI学习总结

    JNI学习总结 标签(空格分隔): java JNI:Java Native Interface,是一种通过java调用本地方法的技术(当然也可以反过来),随着JDK版本的提升,JNI的效率也一直在提 ...

  7. Sumbline编译Less

    Less教程 Sublime Text 2的Less2Css插件介绍与安装 网址 http://fdream.net/blog/article/783.aspx 如果出现node.exe不是内部命令的 ...

  8. php 地址跳转

    header('Location: ' . $sns->getRequestCodeURL());

  9. MVC中Area的使用

    1.Area是什么? MVC 2 中引进了区域的概念,它允许将模型,视图和控制器分成单独的功能节点,换句话说,可以在大型复杂的网站中建立几个区域(模块),每一个区域都有Model,View,Contr ...

  10. [转]left join,right join,inner join区别

    left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录 right join(右联接) 返回包括右表中的所有记录和左表中联结字段相等的记录inner join(等值连接) 只 ...