POJ2104-- K-th Number(主席树静态区间第k大)
[转载]一篇还算可以的文章,关于可持久化线段树http://finaltheory.info/?p=249
无修改的区间第K大
我们先考虑简化的问题:我们要询问整个区间内的第K大。这样我们对值域建线段树,每个节点记录这个区间所包含的元素个数,建树和查询时的区间范围用递归参数传递,然后用二叉查找树的询问方式即可:即如果左边元素个数sum>=K,递归查找左子树第K大,否则递归查找右子树第K – sum大,直到返回叶子的值。
现在我们要回答对于区间[l, r]的第K大询问。如果我们能够得到一个插入原序列中[1, l – 1]元素的线段树,和一颗插入了[1, r]元素的线段树,由于线段树是开在值域上,区间长度是一定的,所以结构也必然是完全相同的,我们可以直接对这两颗线段树进行相减,得到的是相当于插入了区间[l ,r]元素的线段树。注意这里利用到的区间相减性质,实际上是用两颗不同历史版本的线段树进行相减:一颗是插入到第l-1个元素的旧树,一颗是插入到第r元素的新树。
下面是代码
#include <cstdio>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; const int maxn = 1e5+;
int A[maxn],B[maxn],mp[maxn],C[maxn]; // A 为原始数组, B为离散化之后的数组
int n,m,tot,c[maxn*],lson[maxn*],rson[maxn*];
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 update(int root,int pos,int val)
{
int newroot = tot++;
int tmp = newroot;
int l = ,r = n;
c[newroot] = c[root] + val;
while (l < r)
{
int mid = (l + r) >> ;
if (pos <= mid)
{
rson[newroot] = rson[root];
root = lson[root];
lson[newroot] = tot++;
newroot = lson[newroot];
r = mid;
}
else
{
lson[newroot] = lson[root];
root = rson[root];
rson[newroot] = tot++;
newroot = rson[newroot];
l = mid + ;
}
c[newroot] = c[root] + val;
}
return tmp;
}
int query(int l_root,int r_root,int k)
{
int l = , r = n;
while (l < r)
{
int mid = (l + r) >> ;
/*if (c[lson[r_root]] - c[lson[l_root]] >= k)
{
l_root = rson[l_root];
r_root = rson[r_root];
r = mid;
}
else
{
k -= (c[rson[r_root]] - c[rson[l_root]]);
r_root = lson[r_root];
l_root = lson[l_root];
l = mid + 1;
}*/ if (c[lson[r_root]] - c[lson[l_root]] >= k)
{
r = mid;
l_root = lson[l_root];
r_root = lson[r_root];
}
else
{
l = mid + ;
k -= c[lson[r_root]] - c[lson[l_root]];
l_root = rson[l_root];
r_root = rson[r_root];
}
}
return l;
}
int per_root[maxn];
int main(void)
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
while (~scanf ("%d%d",&n,&m))
{
tot = ;
for (int i = ; i <= n; i++)
{
scanf ("%d",A+i);
C[i] = A[i];
} sort(A+,A+n+);
n = unique(A + , A + n + ) - A - ; for (int i = ; i <= n; i++)
{
B[i] = lower_bound(A+,A+n+,C[i]) - A ;
mp[B[i]] = C[i];
}
per_root[] = build(,n);
for (int i = ; i <= n; i++)
{
per_root[i] = update(per_root[i-],B[i],);
}
for (int i = ; i < m; i++)
{
int l,r,k;
scanf ("%d%d%d",&l,&r,&k);
printf("%d\n",mp[query(per_root[l-],per_root[r], k)]);
}
}
return ;
}
POJ2104-- K-th Number(主席树静态区间第k大)的更多相关文章
- poj2104&&poj2761 (主席树&&划分树)主席树静态区间第k大模板
K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 43315 Accepted: 14296 Ca ...
- HDU 2665 Kth number(主席树静态区间第K大)题解
题意:问你区间第k大是谁 思路:主席树就是可持久化线段树,他是由多个历史版本的权值线段树(不是普通线段树)组成的. 具体可以看q学姐的B站视频 代码: #include<cmath> #i ...
- HDU3727--Jewel (主席树 静态区间第k大)
Jewel Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Subm ...
- [poj 2104]主席树+静态区间第k大
题目链接:http://poj.org/problem?id=2104 主席树入门题目,主席树其实就是可持久化权值线段树,rt[i]维护了前i个数中第i大(小)的数出现次数的信息,通过查询两棵树的差即 ...
- 洛谷.3834.[模板]可持久化线段树(主席树 静态区间第k小)
题目链接 //离散化后范围1~cnt不要错 #include<cstdio> #include<cctype> #include<algorithm> //#def ...
- A - 低阶入门膜法 - K-th Number (主席树查询区间第k小)
题目链接:https://cn.vjudge.net/contest/284294#problem/A 题目大意:主席树查询区间第k小. 具体思路:主席树入门. AC代码: #include<i ...
- poj 2104 主席树(区间第k大)
K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 44940 Accepted: 14946 Ca ...
- 主席树--动态区间第k小
主席树--动态区间第\(k\)小 模板题在这里洛谷2617. 先对几个问题做一个总结: 阅读本文需要有主席树的基础,也就是通过区间kth的模板题. 静态整体kth: sort一下找第k小,时间复杂度\ ...
- HDU 5919 - Sequence II (2016CCPC长春) 主席树 (区间第K小+区间不同值个数)
HDU 5919 题意: 动态处理一个序列的区间问题,对于一个给定序列,每次输入区间的左端点和右端点,输出这个区间中:每个数字第一次出现的位子留下, 输出这些位子中最中间的那个,就是(len+1)/2 ...
随机推荐
- db2 存储过程迁移方法
大家在迁移数据库时,存储过程一般也要迁移过去,但一般有两个问题: 1. 非常多存储过程有先后关系(存储过程调用存储过程),假设存储过程数量少,还能手动操作.假设量大,那真是要疯了. 2. 存储过程过大 ...
- laravel实现数据库读写分离配置或者多读写分离配置
config\database.php里 读写分离:'mysql' => array( 'read' => array( 'host' => '192.168.1.1', ), 'w ...
- [转] 在 Linux 中怎样使用cp命令合并目录树
PS:通过cp -r --link a/* b/* merged 硬链接不需要复制 怎样将两个布局相似的目录树合并成一个新的目录树?为理解该问题让我们思考下面的例子. 假设 dir1 和 dir2 目 ...
- Java基础知识强化84:System类之exit()方法和currentTimeMillis()方法
1. exit方法: public static void exit(int status): 终止当前正在运行的Java虚拟机.参数用作状态码:根据惯例,非0的状态码表示异常终止. 调用System ...
- Sending Signals to Processes with kill, killall, and pkill
The Linux kernel allows many signals to be sent to processes. Use man 7 signals for a complete overv ...
- Mysql group_concat
select p.id,p.parent_id,group_concat(distinct(CONCAT("分类名称:",c.name)) order by c.id desc s ...
- pointer-events属性
pointer-events的风格更像JavaScript,它能够: 1.阻止用户的点击动作产生任何效果.阻止缺省鼠标指针的显示3.阻止CSS里的hover和active状态的变化触发事件4.阻止Ja ...
- ASP.NET 页面间数据传递的方法
在做WEB开发时,很多地方会涉及到页面间的数据传递.这几天在完善教务基础系统,遇到了这个问题,上网查了一些资料,现总结如下: 说到页面间数据传递,很多人都会想到通过像Session这样的全局变量,但是 ...
- Php ORM 对象关系映射
ORM的全称是Object Relational Mapping,即对象关系映射.它的实质就是将关系数据(库)中的业务数据用对象的形式表示出来,并通过面向对象(Object-Oriented)的方式将 ...
- 控制弹出div显示在鼠标附近的位置
前一个页面: $("#txt_ocname").click(function () { art.dialog.open("/SelPosAll.aspx", { ...