初涉主席树【在更】

高贵冷艳的主席树……

主席树是什么

是一种数据结构

主席树对于序列$1..i$的每一个前缀各建一颗值域线段树。

很重要的是主席树具有可减性,这是它能够区间操作的重要前提,这有点类似于前缀和的思想。

好的假设我们现在建出了这$n$颗线段树,那么我们的确是可以进行各种区间操作了。但是每颗线段树的空间是$maxn<<4$啊,空间复杂度显然要出事。

回到最初主席树的实现上来:1.它对于前缀建树;2.它建的是值域线段树。

性质一:对于前缀建树

那么相邻之间的两颗树的重复信息是很多的嘛,每次修改$logn$的节点信息,于是我们可以共享其余相同的节点。

性质二:建的是值域线段树

显然值域线段树的构造形态是和所处位置无关的,换句话说就是这$n$颗值域线段树的构造是相同的,只是其节点的$val$不一样。这一点保证了主席树共享节点后的空间复杂度的正确性。

至于如何共享节点,其实也没有什么刁钻的操作。我们只要动态开点,并且继承上一次的节点信息就好了。

以上是静态主席树的大致内容,挂一篇好博客:题解 P3834 【【模板】可持久化线段树 1(主席树)】

主席树的难点实际在于应用而不是其理解(怎么和网络流一样)。

例题

P3834 【模板】可持久化线段树 1(主席树)

题目描述

如题,给定N个正整数构成的序列,将对于指定的闭区间查询其区间内的第K小值。

输入输出格式

输入格式:

第一行包含两个正整数N、M,分别表示序列的长度和查询的个数。

第二行包含N个正整数,表示这个序列各项的数字。

接下来M行每行包含三个整数 l, r, kl,r,k , 表示查询区间 [l, r][l,r] 内的第k小值。

输出格式:

输出包含k行,每行1个正整数,依次表示每一次查询的结果


题目分析

挂代码:

 1 #include<bits/stdc++.h>
 2 const int maxn = 200035;
 3 
 4 struct node
 5 {
 6     int l,r,val,root;
 7 }a[maxn<<5];
 8 int tot,n,m,q;
 9 int x[maxn],b[maxn];
10 
11 int read()
12 {
13     char ch = getchar();
14     int num = 0;
15     bool fl = 0;
16     for (; !isdigit(ch); ch = getchar())
17         if (ch=='-') fl = 1;
18     for (; isdigit(ch); ch = getchar())
19         num = (num<<1)+(num<<3)+ch-48;
20     if (fl) num = -num;
21     return num;
22 }
23 int build(int l, int r)
24 {
25     if (l==r) return ++tot;
26     int rt = ++tot, mid = (l+r)>>1;
27     a[rt].l = build(l, mid);
28     a[rt].r = build(mid+1, r);
29     return rt;
30 }
31 int update(int pre, int l, int r, int x)
32 {
33     int rt = ++tot, mid = (l+r)>>1;
34     a[rt] = a[pre];
35     a[rt].val++;
36     if (l < r){
37         if (x <= mid) a[rt].l = update(a[pre].l, l, mid, x);
38         else a[rt].r = update(a[pre].r, mid+1, r, x);
39     }
40     return rt;
41 }
42 int query(int L, int R, int l, int r, int k)
43 {
44     if (l==r) return l;
45     int val = a[a[R].l].val-a[a[L].l].val, mid = (l+r)>>1;
46     if (k <= val) return query(a[L].l, a[R].l, l, mid, k);
47     return query(a[L].r, a[R].r, mid+1, r, k-val);
48 } 
49 int main()
50 {
51     n = read(), q = read();
52     for (int i=1; i<=n; i++) x[i] = b[i] = read();
53     std::sort(b+1, b+n+1);
54     m = std::unique(b+1, b+n+1)-b-1;
55     a[0].root = build(1, m);
56     for (int i=1; i<=n; i++)
57     {
58         int tt = std::lower_bound(b+1, b+m+1, x[i])-b;
59         a[i].root = update(a[i-1].root, 1, m, tt);
60     }
61     for (int i=1; i<=q; i++)
62     {
63         int l = read(), r = read(), k = read();
64         printf("%d\n",b[query(a[l-1].root, a[r].root, 1, m, k)]);
65     }
66     return 0;
67 }

【在更】

猜你喜欢

转载自www.cnblogs.com/antiquality/p/9156848.html