K-th Number POJ - 2104

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.
 
 
题意:求区间第k大
题解:主席树的板子
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<sstream>
#include<cmath>
#include<stack>
#include<cstdlib>
#include <vector>
#include<queue>
using namespace std; #define ll long long
#define llu unsigned long long
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
const int maxn = 1e5+;
const int mod = 1e9+; int n,q,m,tot;
int a[maxn],t[maxn],T[maxn],lson[maxn*],rson[maxn*],c[maxn*]; void Init_hash()
{
for(int i=;i<=n;i++)
t[i] = a[i];
sort(t+,t++n);
m = unique(t+,t++n)-t-;
} int build(int l,int r)
{
int root = tot++;
c[root] = ;
if (l != r)
{
int mid = (l+r) >> ;
lson[root] = build(l,mid);
rson[root] = build(mid+,r);
}
return root;
}
int Hash(int x)
{
return lower_bound(t+,t++m,x)-t;
}
int update(int root,int pos,int val)
{
int newroot = tot ++,tmp = newroot;
c[newroot] = c[root] + val;
int l = ,r = m;
while(l <r)
{
int mid = (l+r)>>;
if(pos <= mid)
{
lson[newroot] = tot++;
rson[newroot] = rson[root];
newroot = lson[newroot];
root = lson[root];
r = mid;
}
else
{
rson[newroot] = tot ++;
lson[newroot] = lson[root];
newroot = rson[newroot];
root = rson[root];
l = mid + ;
}
c[newroot] = c[root] + val;
}
return tmp; }
int query(int left_root,int right_root,int k)
{
int l = ,r = m;
while(l < r)
{
int mid = (l+r) >> ;
if(c[lson[left_root]] - c[lson[right_root]] >= k)
{
r = mid;
left_root = lson[left_root];
right_root = lson[right_root];
}
else
{
l = mid + ;
k -= c[lson[left_root]] - c[lson[right_root]];
left_root = rson[left_root];
right_root = rson[right_root];
}
}
return l;
}
int main()
{
scanf("%d%d",&n,&q);
tot = ;
for(int i=;i<=n;i++)
scanf("%d",&a[i]);
Init_hash();
T[n+] = build(,m);
for(int i=n;i;i--)
{
int pos = Hash(a[i]);
T[i] = update(T[i+],pos,);
}
while(q--)
{
int l,r,k;
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",t[query(T[l],T[r+],k)]);
}
}
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<stack>
#include<cstdlib>
#include<queue>
#include<set>
#include<string.h>
#include<vector>
#include<deque>
#include<map>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f
#define inf 0x3f3f3f3f
#define eps 1e-4
#define bug printf("*********\n")
#define debug(x) cout<<#x"=["<<x<<"]" <<endl
typedef long long LL;
typedef long long ll;
const int maxn = 2e5 + ;
const int mod = ;
int n,m,a[maxn],root[maxn],cnt;
vector<int>v;
struct node{
int l,r,sum;
}T[maxn * ];
int getid(int x) {
return lower_bound(v.begin(),v.end(),x) - v.begin() + ;
}
void update(int l,int r,int &x,int y,int pos) {
T[++cnt] = T[y],T[cnt].sum ++,x = cnt;
if(l == r) return;
int mid = (l + r) / ;
if(mid >= pos) update(l,mid,T[x].l,T[y].l,pos);
else update(mid + ,r,T[x].r,T[y].r,pos);
}
int query(int l,int r,int x,int y,int k) {
if(l == r) return l;
int mid = (l + r) / ;
int sum = T[T[y].l].sum - T[T[x].l].sum;
if(sum >= k) return query(l,mid,T[x].l,T[y].l,k);
else return query(mid + ,r,T[x].r,T[y].r,k - sum);
}
void init() {
cnt = ;
memset(root,,sizeof root);
}
int main()
{
init();
scanf("%d %d",&n,&m);
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());
for (int i = ; i <= n; ++i)
update(,n,root[i],root[i - ],getid(a[i]));
for (int i = ; i <= m; ++i) {
int x,y,k;
scanf("%d %d %d",&x, &y, &k);
printf("%d\n",v[query(,n,root[x - ],root[y],k) - ]);
}
}
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<stack>
#include<cstdlib>
#include<queue>
#include<set>
#include<string.h>
#include<vector>
#include<deque>
#include<map>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f
#define inf 0x3f3f3f3f
#define eps 1e-4
#define bug printf("*********\n")
#define debug(x) cout<<#x"=["<<x<<"]" <<endl
typedef long long LL;
typedef long long ll;
const int maxn = 2e5 + ;
const int mod = ;
int n,m,a[maxn],root[maxn],cnt;
/*
root:代表每个历史版本线段树的根节点位置
cnt:用作开辟新的树节点
*/
vector<int>v;
struct node{
int l,r,sum;
}T[maxn * ]; //线段树区间统计,sum代表在这个区间数的个数
int getid(int x) { //获取离散数组后的下标
return lower_bound(v.begin(),v.end(),x) - v.begin() + ;
}
/*
update函数:
y代表前一棵树的节点位置,x是后面的节点位置
*/
void update(int l,int r,int &x,int y,int pos) {
//&x 引用节点指针扩展新节点
T[++cnt] = T[y],T[cnt].sum ++,x = cnt; //新开节点,将需要修改的树节点复制到新开辟节点,改变自己的sum
if(l == r) return;
int mid = (l + r) / ;
if(mid >= pos) update(l,mid,T[x].l,T[y].l,pos); //节点左边
else update(mid + ,r,T[x].r,T[y].r,pos); //节点右边
}
int query(int l,int r,int x,int y,int k) {
if(l == r) return l;
int mid = (l + r) / ;
int sum = T[T[y].l].sum - T[T[x].l].sum; //两颗线段树sum做差
if(sum >= k) return query(l,mid,T[x].l,T[y].l,k); //如果当前的结点个数sum比k要大的话,说明第k大的结点在左子树当中,就去遍历左子树
else return query(mid + ,r,T[x].r,T[y].r,k - sum); //如果当前的结点个数sum比k要小的话,说明第k大的结点在右子树当中,而左子树的结点个数是sum个,那就去找右子树中的第k-sum的数
}
void init() {
cnt = ;
memset(root,,sizeof root);
}
int main()
{
init();
scanf("%d %d",&n,&m);
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()); //离散化数组 for (int i = ; i <= n; ++i) {
update(, n, root[i], root[i - ], getid(a[i]));
}
for (int i = ; i <= m; ++i) {
int x,y,k;
scanf("%d %d %d",&x, &y, &k);
printf("%d\n",v[query(,n,root[x - ],root[y],k) - ]);
}
}

K-th Number POJ - 2104的更多相关文章

  1. K-th Number Poj - 2104 主席树

    K-th Number Poj - 2104 主席树 题意 给你n数字,然后有m次询问,询问一段区间内的第k小的数. 解题思路 这个题是限时训练做的题,我不会,看到这个题我开始是拒绝的,虽然题意清晰简 ...

  2. 主席树 【权值线段树】 && 例题K-th Number POJ - 2104

    一.主席树与权值线段树区别 主席树是由许多权值线段树构成,单独的权值线段树只能解决寻找整个区间第k大/小值问题(什么叫整个区间,比如你对区间[1,8]建立一颗对应权值线段树,那么你不能询问区间[2,5 ...

  3. K-th Number POJ - 2104 划分树

    K-th Number You are working for Macrohard company in data structures department. After failing your ...

  4. HDU 2665.Kth number-可持久化线段树(无修改区间第K小)模板 (POJ 2104.K-th Number 、洛谷 P3834 【模板】可持久化线段树 1(主席树)只是输入格式不一样,其他几乎都一样的)

    Kth number Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  5. AC日记——K-th Number poj 2104

    K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 52348   Accepted: 17985 Ca ...

  6. hdu 2665 Kth number (poj 2104 K-th Number) 划分树

    划分树的基本功能是,对一个给定的数组,求区间[l,r]内的第k大(小)数. 划分树的基本思想是分治,每次查询复杂度为O(log(n)),n是数组规模. 具体原理见http://baike.baidu. ...

  7. POJ 2104&HDU 2665 Kth number(主席树入门+离散化)

    K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 50247   Accepted: 17101 Ca ...

  8. poj 2104 K-th Number 主席树+超级详细解释

    poj 2104 K-th Number 主席树+超级详细解释 传送门:K-th Number 题目大意:给出一段数列,让你求[L,R]区间内第几大的数字! 在这里先介绍一下主席树! 如果想了解什么是 ...

  9. poj 2104 K-th Number(主席树,详细有用)

    poj 2104 K-th Number(主席树) 主席树就是持久化的线段树,添加的时候,每更新了一个节点的线段树都被保存下来了. 查询区间[L,R]操作的时候,只需要用第R棵树减去第L-1棵树就是区 ...

随机推荐

  1. Asp.NET MVC+WebAPI跨域调用

    使用jQuery调用WebApi有时会遇到跨域的问题,今天介绍一种可以简单解决跨域问题的方法. 当我们跨域请求WebAPI的时候会提示以下信息: XMLHttpRequest cannot load ...

  2. mybatis + log4j2 问题 java.lang.NoClassDefFoundError: org/apache/logging/log4j/spi/AbstractLoggerWrapper

    root cause java.lang.NoClassDefFoundError: org/apache/logging/log4j/spi/AbstractLoggerWrapper 网上资料比较 ...

  3. 程序员从初级到中级10个秘诀——摘自CSDN

    程序员从初级到中级10个秘诀 1.学习先进的搜索技术.手段和及策略 2.帮助别人 教别人始终是学习一切东西的最好方法之一.相对而言,由于你在开发领域还是个新手,认为自己没什么可教给人家的,这可以理解. ...

  4. android读写SD卡封装的类

    参考了网上的一些资源代码,FileUtils.java: package com.example.test; import java.io.BufferedInputStream; import ja ...

  5. Java中的for循环——通过示例学习Java编程(9)

      作者:CHAITANYA SINGH 来源:https://www.koofun.com/pro/kfpostsdetail?kfpostsid=21 循环用于反复执行同一组语句,直到满足特定条件 ...

  6. Spring AOP初步总结(三)

    最近遇到一个新需求:用户多次点击提交订单发生多次扣款,一开始准备配置数据库事务,但后来发现这种方法白白浪费很多资源,就改为利用接口上的切面对请求做拦截,并将当前登陆的用户存进Redis缓存,废话不说了 ...

  7. li浮动 第二行第一个位置空白

    li浮动 第二行第一个位置空白:解决办法 li加上 vertical-align:bottom;overflow:hidden; 一行字多了 省略号代替: text-overflow: ellipsi ...

  8. [转]vim 快捷键整理

    Linux中vim编辑器的功能非常强大,许多常用快捷键用起来非常方便,这里将我学vim入门时学的一些常用的快捷键分享给大家一下,希望可以帮助你们.  原文地址:http://blog.csdn.net ...

  9. Android 桌面悬浮窗效果实现,仿360手机卫士悬浮窗效果

    首先是一个小的悬浮窗显示的是当前使用了百分之多少的内存,点击一下小悬浮窗,就会弹出一个大的悬浮窗,可以一键加速.好,我们现在就来模拟实现一下类似的效果. 先谈一下基本的实现原理,这种桌面悬浮窗的效果很 ...

  10. 【extjs6学习笔记】0.3 准备: 类库结构2