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

博主sbit。。。。对于高级数据结构深感无力,然后这些东西在OI竟然烂大街了,不搞就整个人都不好了呢。

于是我勇猛的跳进了这个大坑

          ——sbit

区间K大的裸题,在线,无修改。

可以用归并树(\(O(nlog^3n)\)),也可用划分树(\(O(nlogn + mlogn)\))。果断划分树。。。(以后再来看归并树。。。再来看。。。来看。。看。。)

划分树是个什么东西呢?为什么可以做区间k大呢?

想想平衡树做k大时是如何搞的,其实内在原理是一样的。

划分树分两个步骤:建树与询问,这两个步骤相互关联,互相影响。



待update (其实sbit还没完全理解查询)



 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 const int maxn = 100000 + 10;
 5 int val[20][maxn], sorted[maxn], to_left[20][maxn];
 6 int n, m;
 7 void build_tree(int l, int r, int layer) {
 8     if(l == r) return ;
 9     int mid = (l + r) >> 1;
10     int suppose = mid - l + 1;
11     for(int i = l; i <= r; ++i)
12         if(val[layer][i] < sorted[mid])
13             --suppose;
14     int rec_l = l, rec_r = mid + 1;
15     for(int i = l; i <= r; ++i) {
16         if(i == l) {
17             to_left[layer][i] = 0;
18         } else {
19             to_left[layer][i] = to_left[layer][i - 1];
20         }
21         if(val[layer][i] < sorted[mid]) {
22             ++to_left[layer][i];
23             val[layer + 1][rec_l++] = val[layer][i];
24         } else if(val[layer][i] > sorted[mid]) {
25             val[layer + 1][rec_r++] = val[layer][i];
26         } else {
27             if(suppose != 0) {
28                 --suppose;
29                 ++to_left[layer][i];
30                 val[layer + 1][rec_l++] = val[layer][i];
31             } else {
32                 val[layer + 1][rec_r++] = val[layer][i];
33             }
34         }
35     }
36     build_tree(l, mid, layer + 1);
37     build_tree(mid + 1, r, layer + 1);
38 }
39
40 int query(int l, int r, int layer, int ql, int qr, int kth) {
41     if(l == r) return val[layer][l];
42     int s, ss;
43     if(l == ql) {
44         s = 0;
45         ss = to_left[layer][qr];
46     } else {
47         s = to_left[layer][ql - 1];
48         ss = to_left[layer][qr] - s;
49     }
50     int mid = (l + r) >> 1;
51     if(kth <= ss) {
52         return query(l, mid, layer + 1, l + s, l + s + ss - 1, kth);
53     }
54     return query(mid + 1, r, layer + 1, mid + 1 + ql - s - l, mid + 1 + qr - l - s - ss, kth - ss);
55 }
56
57 int main() {
58 #ifndef ONLINE_JUDGE
59     freopen("data.in", "r", stdin); freopen("data.out", "w", stdout);
60 #endif
61     scanf("%d%d", &n, &m);
62     for(int i = 1; i <= n; ++i) {
63         scanf("%d", &sorted[i]);
64         val[0][i] = sorted[i];
65     }
66     sort(sorted + 1, sorted + n + 1);
67     build_tree(1, n, 0);
68     while(m--) {
69         int l, r, k;
70         scanf("%d%d%d", &l, &r, &k);
71         printf("%d\n", query(1, n, 0, l, r, k));
72     }
73     return 0;
74 }

poj2104 划分树 区间K大 在线 无修改,布布扣,bubuko.com

时间: 2024-10-23 13:52:32

poj2104 划分树 区间K大 在线 无修改的相关文章

poj2104 主席树 区间K大 在线 无修改

关于主席树: 主席树(Chairman Tree)是一种离线数据结构,使用函数式线段树维护每一时刻离散之后的数字出现的次数,由于各历史版本的线段树结构一致,可以相减得出区间信息,即该区间内出现的数字和对应的数量,由于在线段树内,左子树代表的数字都小与右子树,便可像平衡树一样进行K大询问.新建一颗树是\(O(logn)\),查询一次也为\(O(logn)\). 比划分树好想&写多了,但是在POJ上比划分树慢一些. CODE: 1 #include <cstdio> 2 #include

【区间k大】HDU 54512 CRB and Queries

通道 题意:区间k大,单点修改 思路:裸,复杂度n(lgn)^2 代码: #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; const int N = 60010 * 5; const int M = 100100 * 4; #define INF 1000000

BZOJ 1901: Zju2112 Dynamic Rankings 区间k大 带修改 在线 线段树套平衡树

之前写线段树套splay数组版..写了6.2k..然后弃疗了.现在发现还是很水的..嘎嘎.. zju过不了,超时. upd:才发现zju是多组数据..TLE一版才发现.然后改了,MLE...手写内存池..尼玛终于过了..附zju2112代码于后. bzoj倒是过了,1A的感觉还是很爽的..可是时间不好看..这就是所谓\(O(nlog^3n)\)的复杂度的可怜之处么? 写挂的地方: insert一定要是传地址指针进去. delete时先把地址指针delete掉,最后把是地址指针指向左儿子or右儿子

HDU 4417 (划分树+区间小于k统计)

题目链接:  http://acm.hdu.edu.cn/showproblem.php?pid=4417 题目大意:给定一个区间,以及一个k值,求该区间内小于等于k值的数的个数.注意区间是从0开始的. 解题思路: 首先这题线段树可以解.方法是维护一个区间最大值max,一个区间点个数s,如果k>max,则ans=s+Q(rson),否则ans=Q(lson). 然后也可以用求区间第K大的划分树来解决,在对原来求第K大的基础上改改就行,方法如下: Build方法同第K大. 对于Query: ①左区

动态求区间K大值(权值线段树)

我们知道我们可以通过主席树来维护静态区间第K大值.我们又知道主席树满足可加性,所以我们可以用树状数组来维护主席树,树状数组的每一个节点都可以开一颗主席树,然后一起做. 我们注意到树状数组的每一棵树都和前一颗树没有关系,so,并不需要可持久化,一个朴素的权值线段树就可以啦. 我们知道普通的线段树是刚开始就把所有的节点都开了,但我们发现并不需要,因为每个点里的操作并不是很多,很大一部分的节点是用不到的,那么我们就可以不开.用Ls 和 Rs 来记左右儿子的地址,随用随开即可. #include<bit

hdu3437 划分树 区间内小于第K大的值得和

Minimum Sum Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 3769    Accepted Submission(s): 872 Problem Description You are given N positive integers, denoted as x0, x1 ... xN-1. Then give you

POJ 2104:K-th Number(主席树静态区间k大)

题目大意:对于一个序列,每次询问区间[l,r]的第k大树. 分析: 主席树模板题 program kthtree; type point=record l,r,s:longint; end; var t:array[0..100000*50]of point; a,b,id,root:array[0..100000]of longint; n,i,m,x,y,k,v,len:longint; procedure qsort(l,h:longint); var i,j,t,m:longint; b

[BZOJ 1112] [POI2008] 砖块Klo 【区间K大】

题目链接:BZOJ - 1112 题目分析 枚举每一个长度为k的连续区间,求出这个区间的最优答案,更新全局答案. 可以发现,这个区间的所有柱子最终都变成这k个数的中位数时最优,那么我们就需要查询这个区间的中位数了. 找到中位数之后,我们还应该求出这个区间内小于中位数的数的和,大于中位数的数的和,从而求出操作步数. 这些需要求的值可以用线段树或平衡树来写,我写的是线段树,但是实际上这是一道POI的题目,在MAIN上的空间限制只有35MB,线段树应该是不行的. 因为平衡树只需要 O(n) 空间,所以

FZU 2237 中位数 主席树 树上k大

#include <cstdio> #include <cstring> #include <queue> #include <set> #include <stack> #include <cstdlib> #include <algorithm> #include <time.h> #include <vector> #include <cmath> using namespace