poj 2104 K-th Number(主席树,详细有用)
poj 2104 K-th Number(主席树)
| Time Limit: 20000MS | Memory Limit: 65536K | |
| Total Submissions: 62232 | Accepted: 21860 | |
| 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
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


添加的这个节点离散化之后是1,也就是最左下角的那个节点。

总共是7个数,离散化管它有几个不重复的数,按照最大情况7个个数来算就对了。
所以这7个数是依次会被放到这7个叶子节点上面的来。
数的序列是1 5 2 6 3 7 4
第一个数是1,离散化之后也是1,所以会被放到最左下角3那个位置,所以就是上图右边更新的情况,(注意看节点的下标)。


第5棵树根节点的左边有3个,第一棵树根节点左边只有一个,多3-1=2个,但是我要找的是3大的,所以必定在第五棵树减去第一颗树的右边的第一个。



测试代码(后面有AC代码)
#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN = ;
const int N = MAXN*;
int n,m,q,tot;
int T[MAXN],A[MAXN],t[MAXN];
//详单于结构体
int lson[N],rson[N],sum[N];
vector<int>V;
int getid(int x) //离散化
{
return lower_bound(V.begin(),V.end(),x)-V.begin()+;
}
int build(int l,int r) //建立一棵空树
{
int rt = tot++;
sum[rt] = ;//初始化,相当于初始化结构体中的sum元素
//不是叶子节点
if(l!=r){
int mid=(l+r)>>;
lson[rt] = build(l,mid);
rson[rt] = build(mid+,r);
}
return rt;
} //比如说第一组数是(0,1),表示继承的第0棵树,然后插入的那个数的id是1
int update(int rt,int pos) //把数组中的元素一次加入新的线段树中
{
int nrt = tot++;//相当于节点13
int tmp = nrt;
//sum[13]=sum[0]+1,这是插入第一个点的情况,表示sum[13]第一棵树比 sum[0]第0棵树多了一个元素
sum[nrt] = sum[rt]+;
int l=,r=m;//相当于从根节点开始更新
while(l<r) {//不停的从上往下(二分)去更新到那条路径的叶子节点
int mid = (l+r)>>;
//插入节点在线段树的左边
if(pos<=mid) {
lson[nrt] = tot++;//左边的节点就是我们新创建的这个节点,相当于节点14
rson[nrt] = rson[rt];//右边节点就直接继承前一棵树 ,相当于节点8
nrt = lson[nrt];//让13节点向下走到14号节点
rt = lson[rt];//前一棵树继续往下走,把前一棵树0号节点的左孩子的值赋值给rt,方便让新的这棵树找得到5号节点,4号节点
r = mid;//二分
}else {
rson[nrt] = tot++;
lson[nrt] = lson[rt];//左边直接继承前一棵树
nrt = rson[nrt];
rt = rson[rt];
l=mid+;
}
sum[nrt] = sum[rt]+;//节点在前一棵树的基础上面个数+1
}
return tmp;
} //第y棵树减第x-1棵树就是xy之间的元素,然后找到第k大的即可
//printf("%d\n",V[query(T[x-1],T[y],k)-1]);
//相当于是在两棵树的差树的那颗树上面找
int query(int lrt,int rrt,int k)
{
int l=,r=m;//从根节点开始找
while(l<r) {//二分找
int mid = (l+r)>>;
int cnt = sum[lson[rrt]] - sum[lson[lrt]];//找到有多少个数目
if(cnt>=k) {
r = mid;
lrt = lson[lrt];
rrt = lson[rrt];
} else {
l = mid+;
k-=cnt;//跑到右边去就要把左边的减掉
lrt = rson[lrt];//第一棵树和第五课树都去右孩子,然后是找差值
rrt = rson[rrt];
}
}
return l;
}
//测试主席树
void print(){
cout<<"i"<<" "<<"lson[i]"<<" "<<"rson[i]"<<" "<<"sum[i]"<<" "<<endl;
for(int i=;i<=*n;i++){
cout<<i<<" "<<lson[i]<<" "<<rson[i]<<" "<<sum[i]<<" "<<endl;
}
}
//测试T数组
void printT(){
cout<<"i"<<" "<<"T[i]"<<" "<<endl;
for(int i=;i<=n;i++){
cout<<i<<" "<<T[i]<<" "<<endl;
}
}
int main()
{
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
//n个数q个操作
scanf("%d%d",&n,&q);tot=;
//A[i]存那些数
for(int i=;i<=n;i++) {
scanf("%d",&A[i]);
V.push_back(A[i]);
}
sort(V.begin(),V.end());
V.erase(unique(V.begin(),V.end()),V.end());
//上面一部分是离散化
m=V.size();//找到不重复的元素的个数
cout<<m<<endl; T[] = build(,m);//建1到m的树
cout<<"tot: "<<tot<<endl;
print();
// cout<<T[0]<<endl;
printT();
for(int i=;i<=n;i++) {
T[i] = update(T[i-],getid(A[i]));
cout<<i<<" "<<getid(A[i])<<endl;
}
printT();
while(q--) {
int x,y,k;
scanf("%d%d%d",&x,&y,&k);
//第y棵树减第x-1棵树就是xy之间的元素,然后找到第k大的即可
//最后一个-1是因为V是从0开始
printf("%d\n",V[query(T[x-],T[y],k)-]);
}
print();
return ;
}
AC代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN = ;
const int N = MAXN*;
int n,m,q,tot;
int T[MAXN],A[MAXN],t[MAXN];
int lson[N],rson[N],sum[N];
vector<int>V;
int getid(int x) //离散化
{
return lower_bound(V.begin(),V.end(),x)-V.begin()+;
}
int build(int l,int r) //建立一棵空树
{
int rt = tot++;
sum[rt] = ;
if(l!=r){
int mid=(l+r)>>;
lson[rt] = build(l,mid);
rson[rt] = build(mid+,r);
}
return rt;
} int update(int rt,int pos) //把数组中的元素一次加入新的线段树中
{
int nrt = tot++;
int tmp = nrt;
sum[nrt] = sum[rt]+;
int l=,r=m;
while(l<r) {
int mid = (l+r)>>;
if(pos<=mid) {
lson[nrt] = tot++;
rson[nrt] = rson[rt];
nrt = lson[nrt];
rt = lson[rt];
r = mid;
}else {
rson[nrt] = tot++;
lson[nrt] = lson[rt];
nrt = rson[nrt];
rt = rson[rt];
l=mid+;
}
sum[nrt] = sum[rt]+;
}
return tmp;
} int query(int lrt,int rrt,int k)
{
int l=,r=m;
while(l<r) {
int mid = (l+r)>>;
int cnt = sum[lson[rrt]] - sum[lson[lrt]];
if(cnt>=k) {
r = mid;
lrt = lson[lrt];
rrt = lson[rrt];
} else {
l = mid+;
k-=cnt;
lrt = rson[lrt];
rrt = rson[rrt];
}
}
return l;
}
int main()
{//freopen("in.txt","r",stdin);
scanf("%d%d",&n,&q);tot=;
for(int i=;i<=n;i++) {
scanf("%d",&A[i]);
V.push_back(A[i]);
}
sort(V.begin(),V.end());
V.erase(unique(V.begin(),V.end()),V.end());
m=V.size();
T[] = build(,m);
for(int i=;i<=n;i++) {
T[i] = update(T[i-],getid(A[i]));
}
while(q--) {
int x,y,k;
scanf("%d%d%d",&x,&y,&k);
printf("%d\n",V[query(T[x-],T[y],k)-]);
}
return ;
}
poj 2104 K-th Number(主席树,详细有用)的更多相关文章
- 【POJ 2104】 K-th Number 主席树模板题
达神主席树讲解传送门:http://blog.csdn.net/dad3zz/article/details/50638026 2016-02-23:真的是模板题诶,主席树模板水过.今天新校网不好,没 ...
- 静态区间第k大(主席树)
POJ 2104为例(主席树入门题) 思想: 可持久化线段树,也叫作函数式线段树,也叫主席树(高大上). 可持久化数据结构(Persistent data structure):利用函数式编程的思想使 ...
- poj 2104 K-th Number 主席树+超级详细解释
poj 2104 K-th Number 主席树+超级详细解释 传送门:K-th Number 题目大意:给出一段数列,让你求[L,R]区间内第几大的数字! 在这里先介绍一下主席树! 如果想了解什么是 ...
- poj2104 k-th number 主席树入门讲解
poj2104 k-th number 主席树入门讲解 定义:主席树是一种可持久化的线段树 又叫函数式线段树 刚开始学是不是觉得很蒙逼啊 其实我也是 主席树说简单了 就是 保留你每一步操作完成之后 ...
- 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-th Number ( 求取区间 K 大值 || 主席树 || 离线线段树)
题意 : 给出一个含有 N 个数的序列,然后有 M 次问询,每次问询包含 ( L, R, K ) 要求你给出 L 到 R 这个区间的第 K 大是几 分析 : 求取区间 K 大值是个经典的问题,可以使用 ...
- POJ 2104:K-th Number(主席树静态区间k大)
题目大意:对于一个序列,每次询问区间[l,r]的第k大树. 分析: 主席树模板题 program kthtree; type point=record l,r,s:longint; end; var ...
- SPOJ MKTHNUM & POJ 2104 - K-th Number - [主席树模板题]
题目链接:http://poj.org/problem?id=2104 Description You are working for Macrohard company in data struct ...
- poj 2104 K-th Number(主席树 视频)
K-th Number 题意: 给你一些数,让你求一个区间内,第k大的数是多少. 题解: 主席树第一题,看的qsc视频写的,戳戳戳 学到了unique函数,他的作用是:把相邻的重复的放到后面,返回值是 ...
- Poj 2104 K-th Number(主席树&&整体二分)
K-th Number Time Limit: 20000MS Memory Limit: 65536K Case Time Limit: 2000MS Description You are wor ...
随机推荐
- Linux下ifconfig不显示ip地址问题总结
问题一:ifconfig之后只显示lo,没有看到eth0 ? eth0设置不正确,导致无法正常启动,修改eth0配置文件就好 ubuntu 12.04的网络设置文件是/etc/network/inte ...
- public private protected
初学C++的朋友经常在类中看到public,protected,private以及它们在继承中表示的一些访问范围,很容易搞糊涂.今天本文就来十分分析一下C++中public.protected及pri ...
- Vue2.0 —生命周期和钩子函数
vue生命周期简介 咱们从上图可以很明显的看出现在vue2.0都包括了哪些生命周期的函数了. 生命周期探究 对于执行顺序和什么时候执行,看上面两个图基本有个了解了.下面我们将结合代码去看看钩子函数的执 ...
- returnValue of Chrome
说实话,我一看到这个returnValue就有点反感,感觉这个就是IE式的老套的用法,因为项目中有用到就了解了下,以下主要是一些我的理解和发现吧. PS:returnValue是window的属性,s ...
- 关闭的语句: next、关闭的 Resultset: next、关闭的连接: next问题
如果在rs.next()之前关闭了Statement或PreparedStatement,会导致下面的异常: java.sql.SQLException: 关闭的语句: next 如果在rs.next ...
- 题解 洛谷P3203/BZOJ2002【[HNOI2010]弹飞绵羊】
裸的LCT,关键是要怎么连边,怎么将这种弹飞关系转化成连边就行了. 那么我们可以这样连边: 一个节点i的爸爸就是i+ki. 没有i+ki那么就被弹飞了,即\(i\)的爸爸是虚拟节点n+1. 那么怎么求 ...
- Java垃圾回收简介
Java关键术语 JavaAPI:一系列帮助开发者创建Java应用程序的封装好的库. Java 开发工具包 (JDK):一系列工具帮助开发者创建Java应用程序.JDK包含工具编译.运行.打包.分发和 ...
- Django-F和Q函数作用与使用
F函数 能够解析对现有查询对象的引用的对象. obj = Score.objects.get(stuid=') obj.score += 1 obj.order.save() 执行出的SQL语句 wh ...
- 从“菜鸟”码农到“资深”架构师,我到底经历了什么?--------http://baijiahao.baidu.com/s?id=1585813883835208757&wfr=spider&for=pc
http://baijiahao.baidu.com/s?id=1585813883835208757&wfr=spider&for=pc
- noip模拟赛 算
[问题背景]zhx 帮他妹子做数学题.[问题描述]求: 如 N=3, M=3, 这个值为 1^1+1^2+1^3+2^1+2^2+2^3+3^1+3^2+3^3=56. [输入格式]仅一行, 包含两个 ...