poj2104

题意

给出一个序列,每次查询一个区间,要求告诉这个区间排序后的第k个数。

分析

划分树模板,O(mlogn)。

  1. 建树。根据排序之后的数组,对于一个区间,找到中点的数,将整个区间分为左右子树(在子区间内数与数的相对位置保持不变),递归向下分割。
  2. 查询。toleft[p][i] 表示第 p 层前 i 个数中有多少个整数分入下一层。查询最重要的是确定新的查询区间,若递归查询左区间,则新的子区间的左边一定是上一层区间 [L, l - 1] 里的 toleft[dep][l-1] - toleft[dep][L-1] 个整数,那么 newl = L + toleft[dep][l-1] - toleft[dep][L-1],[l, r] 区间内有cnt = toleft[dep][r] - toleft[dep][l - 1] 个数,所以 newr = newl + cnt - 1;查询右区间则要先确定 newr 的值,[r+1, R] 中有 c = toleft[dep][R] - toleft[dep][r] 个整数位于左子区间的右方,所以查询区间 r 要向右移 c 个数,newr = r + c,newl = newr - (r - l - cnt)。

code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int INF = 1e9;
const int MAXN = 1e5 + 5;
const int LOG_N = 30;
// tree[dep][i] 第dep层第i个位置的数值
int tree[LOG_N][MAXN];
int sorted[MAXN];
// toleft[p][i] 第p层前i个数中有多少个整数分入下一层
int toleft[LOG_N][MAXN]; void build(int l, int r, int dep)
{
if(l == r) return;
int mid = (l + r) / 2;
int same = mid - l + 1; // 和中点数相同的数的个数
for(int i = l; i <= r; i++)
if(tree[dep][i] < sorted[mid]) same--;
int lpos = l, rpos = mid + 1;
for(int i = l; i <= r; i++)
{
if(tree[dep][i] < sorted[mid])
tree[dep + 1][lpos++] = tree[dep][i];
else if(tree[dep][i] == sorted[mid] && same)
{
tree[dep + 1][lpos++] = tree[dep][i];
same--;
}
else tree[dep + 1][rpos++] = tree[dep][i];
toleft[dep][i] = toleft[dep][l - 1] + lpos - l;
}
build(l, mid, dep + 1);
build(mid + 1, r, dep + 1);
}
// [L,R]里查询子区间[l,r]第k小的数
int query(int L, int R, int l, int r, int dep, int k)
{
if(l == r) return tree[dep][l];
int mid = (L + R) / 2;
// 有多少个查询区间内的节点会进入下一层的左子树
int cnt = toleft[dep][r] - toleft[dep][l - 1];
if(cnt >= k)
{
int newl = L + toleft[dep][l - 1] - toleft[dep][L - 1];
int newr = newl + cnt - 1;
return query(L, mid, newl, newr, dep + 1, k);
}
else
{
int newr = r + toleft[dep][R] - toleft[dep][r];
int newl = newr - (r - l - cnt);
return query(mid + 1, R, newl, newr, dep + 1, k - cnt);
}
}
int main()
{
int n, m;
while(~scanf("%d%d", &n, &m))
{
for(int i = 1; i <= n; i++)
{
scanf("%d", &sorted[i]);
tree[0][i] = sorted[i];
}
sort(sorted + 1, sorted + n + 1);
build(1, n, 0);
while(m--)
{
int l, r, k;
scanf("%d%d%d", &l, &r, &k);
printf("%d\n", query(1, n, l, r, 0, k));
}
}
return 0;
}

poj2104(划分树模板)的更多相关文章

  1. poj2104(划分树模板)

    poj2104 题意 给出一个序列,每次查询一个区间,要求告诉这个区间排序后的第k个数. 分析 划分树模板,O(mlogn). 建树.根据排序之后的数组,对于一个区间,找到中点的数,将整个区间分为左右 ...

  2. hdu2665 && poj2104划分树

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

  3. hdu 2665 Kth number(划分树模板)

    http://acm.hdu.edu.cn/showproblem.php?pid=2665 [ poj 2104 2761 ]  改变一下输入就可以过 http://poj.org/problem? ...

  4. HDU-3743 Minimum Sum,划分树模板

    Minimum Sum 被这个题坑了一下午,原来只需找一个最中间的数即可,我以为是平均数. 题意:找一个数使得这个数和区间内所有数的差的绝对值最小.输出最小值. 开始用线段树来了一发果断T了,然后各种 ...

  5. VIJOS P1081 野生动物园 SBT、划分树模板

    [描述] cjBBteam拥有一个很大的野生动物园.这个动物园坐落在一个狭长的山谷内,这个区域从南到北被划分成N个区域,每个区域都饲养着一头狮子.这些狮子从北到南编号为1,2,3,…,N.每头狮子都有 ...

  6. poj2104 划分树 区间K大 在线 无修改

    博主sbit....对于高级数据结构深感无力,然后这些东西在OI竟然烂大街了,不搞就整个人都不好了呢. 于是我勇猛的跳进了这个大坑 ——sbit 区间K大的裸题,在线,无修改. 可以用归并树(\(O( ...

  7. poj 2104 (划分树模板)

    Description You are working for Macrohard company in data structures department. After failing your ...

  8. POJ2104 K-th Number 划分树 模板题啊

    /*Source Code Problem: 2104 User: 96655 Memory: 14808K Time: 1282MS Language: G++ Result: Accepted S ...

  9. poj2104 主席树模板题

    题意 给出n个数字组成的数字序列,有m组询问.每次询问包含三个数字l,r,k.对于每个询问输出序列区间[l,r]中第k大的数字. 分析 这是主席树的模板题,套板子就可以 #include <cs ...

随机推荐

  1. 嵌入式(Embedded System)笔记 —— Cortex-M3 Introduction and Basics(上)

    随着课内的学习,我想把每节课所学记录下来,以作查阅.以饲读者.由于我所上的是英文班课程,因此我将把关键术语的英文给出,甚至有些内容直接使用英文. 本次所介绍内容是关于Cortex-M3的基础内容. - ...

  2. 二叉树 【转】http://blog.csdn.net/sjf0115/article/details/8645991

    //二叉树 #include<iostream> #include<stack> #include<queue> using namespace std; //二叉 ...

  3. Scrapy爬取到的中文数据乱码问题处理

    Scrapy爬取到中文数据默认是 Unicode编码的,于是显示是这样的: "country": ["\u56fd\u4ea7\u6c7d\u8f66\u6807\u5f ...

  4. Python 的音乐库

    前言 其实处理这个用 Matlab 最方便,之前把 guitar-synthesizer 从 Matlab 移植到 Python,过程中更是体会到了这一点. 不过 Matlab 安装包又大,启动又慢, ...

  5. 第二阶段团队冲刺-four

    昨天: 绘制logo. 今天: 用servlet完成名单打印功能. 遇到的问题: servlet中的获得的路径不是想要的.

  6. 基于linux操作系统安装、使用redis详解

    服务端安装 Redis的官方下载站是http://redis.io/download,可以去上面下载最新的安装程序下来,我写此文章时的的稳定版本是2.6.11. 步骤一: 下载Redis 进入软件安装 ...

  7. 【bzoj5047】空间传送装置 堆优化Dijkstra

    题目描述 n个点e条边的有向图,每条边是m种类型之一.第i种类型在第x时刻通过所花费的时间为$(a_i*x+b_i)\mod c_i+d_i$.可以在某个点停留.问:在s时刻从1号点出发,到达每个点所 ...

  8. Python字符串相关

    #字符串的相关操作 #基本操作 #+ 字符串连接操作 str1 = '来是come走是go' str2 = '点头yes摇头no' result = str1 + str2 print(result) ...

  9. [bzoj1798][Ahoi2009]Seq 维护序列seq ([洛谷P3373]【模板】线段树 2)

    题目大意:有$n$个数,有$m$个操作,有三种: $1\;l\;r\;x:$把区间$[l,r]$内的数乘上$x$ $2\;l\;r\;x:$把区间$[l,r]$内的数加上$x$ $3\;l\;r:$询 ...

  10. hdu 3717 二分+队列维护

    思路:已知当前的总长度和为len,当前的伤害为sum,伤害次数为 num.那么对下一个点的伤害值sum=sum+2*len+num: 这个是通过(x+1)^2展开化简就能得到. #include< ...