POJ 2104 HDU 2665 主席树 解决区间第K大
两道题都是区间第K大询问,数据规模基本相同。
解决这种问题, 可以采用平方划分(块状表)复杂度也可以接受,但是实际表现比主席树差得多。
这里大致讲一下我对主席树的理解。
首先,如果对于某个区间【L,R】,对这个区间排序后,我们构造出了线段树, 每个值在这个子区间出现了几次都可以从线段树中查询,我们就可以在对数时间解决询问。
现在的问题就是怎样在时空复杂度O(nlogn)的时间内构造出这么多的线段树!
1.首先对原序列a排序并删去重复得到新序列b
2.对a的每个前缀构造线段树,即a的前i个数出现在b的[L,R]中的个数。
3.相邻前缀的线段树只有一条边不同,故每次只需要增加logn个点,总的空间复杂度O(nlogn)
4.前缀线段树的可加性,rt[r]-rt[l-1]就表示了原序列a[l,r]在新序列b[L,R]的数量。
代码很清晰,参照代码和上述4个性质,应该可以很快理解主席树。
一句话总结一下, 在本题中, 主席树就的功能就是快速的告诉我们:
原序列a的子序列a[l,r]在a排序后的序列b的子序列[L,R]中的个数。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100000 + 5; int a[N], b[N], rt[N * 20], ls[N * 20], rs[N * 20], sum[N * 20]; int n, k, tot, sz, ql, qr, x, q, T; void Build(int& o, int l, int r){
o = ++ tot;
sum[o] = 0;
if(l == r) return;
int m = (l + r) >> 1;
Build(ls[o], l, m);
Build(rs[o], m + 1, r);
} void update(int& o, int l, int r, int last, int p){
o = ++ tot;
ls[o] = ls[last];
rs[o] = rs[last];
sum[o] = sum[last] + 1;
if(l == r) return;
int m = (l + r) >> 1;
if(p <= b[m]) update(ls[o], l, m, ls[last], p);
else update(rs[o], m + 1, r, rs[last], p);
} int query(int ss, int tt, int l, int r, int k){
if(l == r) return l;
int m = (l + r) >> 1;
int cnt = sum[ls[tt]] - sum[ls[ss]];
if(k <= cnt) return query(ls[ss], ls[tt], l, m, k);
else return query(rs[ss], rs[tt], m + 1, r, k - cnt);
} void work(){
scanf("%d%d%d", &ql, &qr, &x);
int ans = query(rt[ql - 1], rt[qr], 1, sz, x);
printf("%d\n", b[ans]);
} int main(){freopen("t.txt","r",stdin);
T=1;
while(T--){
scanf("%d%d", &n, &q);
for(int i = 1; i <= n; i ++) scanf("%d", a + i), b[i] = a[i];
sort(b + 1, b + n + 1);
sz = unique(b + 1, b + n + 1) - (b + 1);
tot = 0;
Build(rt[0],1, sz);
//for(int i = 0; i <= 4 * n; i ++)printf("%d,rt = %d,ls = %d, rs = %d, sum = %d\n", i, rt[i], ls[i], rs[i], sum[i]);
//for(int i = 1; i <= n; i ++)a[i] = lower_bound(b + 1, b + sz + 1, a[i]) - b;
for(int i = 1; i <= n; i ++)update(rt[i], 1, sz, rt[i - 1], a[i]);
// for(int i = 0; i <= 5 * n; i ++)printf("%d,rt = %d,ls = %d, rs = %d, sum = %d\n", i, rt[i], ls[i], rs[i], sum[i]);
while(q --)work();
}
return 0;
}
POJ 2104 HDU 2665 主席树 解决区间第K大的更多相关文章
- poj 2104 主席树(区间第k大)
K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 44940 Accepted: 14946 Ca ...
- HDU 2665 Kth number(主席树静态区间第K大)题解
题意:问你区间第k大是谁 思路:主席树就是可持久化线段树,他是由多个历史版本的权值线段树(不是普通线段树)组成的. 具体可以看q学姐的B站视频 代码: #include<cmath> #i ...
- poj2104&&poj2761 (主席树&&划分树)主席树静态区间第k大模板
K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 43315 Accepted: 14296 Ca ...
- POJ2104-- K-th Number(主席树静态区间第k大)
[转载]一篇还算可以的文章,关于可持久化线段树http://finaltheory.info/?p=249 无修改的区间第K大 我们先考虑简化的问题:我们要询问整个区间内的第K大.这样我们对值域建线段 ...
- [poj 2104]主席树+静态区间第k大
题目链接:http://poj.org/problem?id=2104 主席树入门题目,主席树其实就是可持久化权值线段树,rt[i]维护了前i个数中第i大(小)的数出现次数的信息,通过查询两棵树的差即 ...
- Super Mario HDU - 4417 (主席树询问区间比k小的个数)
Mario is world-famous plumber. His “burly” figure and amazing jumping ability reminded in our memory ...
- 主席树入门(区间第k大)
主席树入门 时隔5个月,我又来填主席树的坑了,现在才发现学算法真的要懂了之后,再自己调试,慢慢写出来,如果不懂,就只会按照代码敲,是不会有任何提升的,都不如不照着敲. 所以搞算法一定要弄清原理,和代码 ...
- HDU3727--Jewel (主席树 静态区间第k大)
Jewel Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Subm ...
- POJ 2104&HDU 2665 Kth number(主席树入门+离散化)
K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 50247 Accepted: 17101 Ca ...
随机推荐
- Mongo索引学习笔记
索引使用场景 优:加快查询速度 劣:增删改会产生额外的开销.占用空间 tips: 返回集合中一半以上的数据,全表扫描的效率高 索引基础 基础操作 查看索引:db.test.getIndexes() 创 ...
- PHP:Mysql判断KEY是否存在 如果存在走修改 如果不存在走添加
文章来源:http://www.cnblogs.com/hello-tl/p/7738113.html 0.PHP代码 <?php /** * POST 传参 * * 例子 添加修改 使用同一个 ...
- Python中的数据类型之字符串
字符串的定义,可是使用类似下面的方式 name = "hello python" Python 中字符串自带了一些常用的方法,比如: title() #用来将每个单词首字母大写up ...
- 确定协议-通过分析系统阶段需要知道该系统能不能进行性能测试-Omnipeek
- hdu 4871 树的分治+最短路记录路径
/* 题意:给你一些节点和一些边,求最短路径树上是k个节点的最长的路径数. 解:1.求出最短路径树--spfa加记录 2.树上进行操作--树的分治,分别处理子树进行补集等运算 */ #include& ...
- [K/3Cloud] 调用其他界面时通过Session传递对象参数
DynamicFormShowParameter参数的CustomParams参数列表只支持string类型的参数,对于复杂参数的传递需要通过单据View对象的共享Session来完成,如: 在调用界 ...
- Oracle锁表数据查询及解决方法
首先:查询数据那些表被锁定1. SELECT l.session_id sid, s.serial#, l.locked_mode,l.oracle_username, l.os_user_name, ...
- [NOIP2004] 提高组 洛谷P1092 虫食算
题目描述 所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母.来看一个简单的例子: 43#9865#045 +8468#6633 44445509678 其中# ...
- linux 常见名词及命令(三)
tar 用于对文件打包压缩或解压. 示例: 打包并压缩文件:tar -czvf 压缩包名.tar.gz 文件名 解压并展开压缩包:tar -zxvf 压缩包名.tar.gz -c 创建压缩文件 -x ...
- SharedPreferences保存用户偏好参数
package com.example.administrator.myapplication; import android.content.Context; import android.cont ...