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 ...
随机推荐
- C_动态库|静态库
动态库 动态链接库简称DLL,同时以.dll 为后缀,主要用于提供代码和数据 dll 并不是所有数据都能被访问到,必须要进行导出 动态链接库在内存中始终只保存了一份数据,起到了节约内存的作用 生成动态 ...
- CPU 的寻址方式
来源https://baike.baidu.com/item/%E5%AF%BB%E5%9D%80%E6%96%B9%E5%BC%8F/3210621?fr=aladdin 寻址方式就是处理器根据指令 ...
- PMP 学习心得
前两天刚考完 PMP,松了一口气,终于考完了,虽然心里有点慌,不知道自己会不会过.学习 PMP 这三个月还是很充实的.不断的看视频,做题目,功夫不负有心人,也算是学到了一些东西.至少知道了一个项目的启 ...
- C++ volatile关键字(转)
文章来源: http://hedengcheng.com/?p=725 https://www.cnblogs.com/god-of-death/p/7852394.html 1.基本概念 volat ...
- UVA - 1608 Non-boring sequences(分治法)
题目: 如果一个序列的任意连续的子序列中至少有一个只出现一次的元素,则称这个序列是不无聊的.输入一个n(n≤200000)个元素的序列A(各个元素均为109以内的非负整数),判断它是不是不无聊的. 思 ...
- python whl模块安装方法
搞了半个小时可算是安装上去了 做法 ①先cmd输入Python看一下自己的Python是什么版本的,以及自己的平台,我这里是win32以及python3.6 ②然后去寻找合适的whl,注意cp就是版本 ...
- Win10中创建Hyper-V虚拟机
Win10虚拟机创建方法方法 1 开始菜单->所有应用->Windows系统->控制面板,程序->启用或关闭Windows功能,勾选Hyper-V下所有选项 如果Hyper-V ...
- linux time-统计给定命令所花费的总时间
推荐:更多linux 性能监测与优化 关注:linux命令大全 time命令用于统计给定命令所花费的总时间. 语法 time(参数) 参数 指令:指定需要运行的额指令及其参数. 实例 当测试一个程序或 ...
- Journals in Fluid Mechanics
journal of fluid mechanics physics of fluids annual review of fluid mechanics
- 腾讯云:搭建 Node.js 环境
搭建 Node.js 环境 安装 Node.js 环境 任务时间:5min ~ 10min Node.js 是运行在服务端的 JavaScript, 是基于 Chrome JavaScript V8 ...