主席树搞了一个多星期TAT,,,,,,也只是大致领悟而已!!!

主席树又称函数式线段树,顾名思义,也就是通过函数来实现的线段树,至于为什么叫主席树,那是因为是fotile主席创建出来的这个数据结构(其实貌似是当初主席不会划分树而自己想出来的另一个处理方式。。。。是不是很吊呢? ORZ...)不扯了,切入正题。

主席树就是利用函数式编程的思想来使线段树支持询问历史版本、同时充分利用它们之间的共同数据来减少时间和空间消耗的增强版的线段树。

     很多问题如果用线段树处理的话需要采用离线思想,若用主席树则可直接在线处理。故很多时候离线线段树求解可以转化为在线主席树求解。注意,主席树本质就是线段树,变化就在其实现可持久化,后一刻可以参考前一刻的状态,二者共同部分很多。一颗线段树的节点维护的是当前节点对应区间的信息,倘若每次区间都不一样,就会给处理带来一些困难。有时可以直接细分区间然后合并,此种情况线段树可以直接搞定;但有时无法通过直接划分区间来求解,如频繁询问区间第k小元素,当然,此问题有比较特殊的数据结构-划分树。其实还有一个叫做归并树,是根据归并排序实现的,每个节点保存的是该区间归并排序后的序列,因此,时间、空间复杂度都及其高, 所以一般不推荐去用。当然,主席树也是可以解决的。

附上归并树代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <vector>
 4 #include <algorithm>
 5 using namespace std;
 6 const int N = 100000 + 5;
 7 
 8 vector<int>node[N << 2];
 9 
10 int T, n, q, ql, qr, ans, k, sz;
11 
12 int a[N], b[N];
13 
14 inline int read(){//快速读入是邪教
15     char c;
16     int ret = 0;
17     int sgn = 1;
18     do{c = getchar();}while((c < '0' || c > '9') && c != '-');
19     if(c == '-') sgn = -1; else ret = c - '0';
20     while((c = getchar()) >= '0' && c <= '9') ret = ret * 10 + (c - '0');
21     return sgn * ret;
22 }
23 
24 void Build(int o, int l, int r){
25     node[o].clear();
26     if(l == r){
27         node[o].push_back(a[l]);
28         return ;
29     }
30     int m = (l + r) >> 1;
31     Build(o << 1, l, m);
32     Build(o << 1|1, m + 1, r);
33     node[o].resize(r - l + 1);
34     merge(node[o<<1].begin(), node[o<<1].end(), node[o<<1|1].begin(), node[o<<1|1].end(), node[o].begin());
35 }
36 
37 int query(int o, int l, int r, int x){
38     //if(ql > r || qr < l) return 0;
39     if(ql <= l && qr >= r)  return upper_bound(node[o].begin(), node[o].end(), x) - node[o].begin();
40     int m = (l + r) >> 1;
41     int ret = 0;
42     if(ql <= m)ret += query(o << 1, l, m, x);
43     if(qr > m)ret += query(o << 1|1, m + 1, r, x);
44     return ret;
45 }
46 
47 void work(){
48     //ql = read();
49     //qr = read();
50     //k = read();
51     scanf("%d%d%d", &ql, &qr, &k);
52     int lt = 1, rt = sz;
53    while(lt <= rt){
54        int md = (lt + rt) >> 1;
55        if(query(1, 1, n, b[md]) >= k)rt = md - 1;
56        else lt = md + 1;
57    } 
58    printf("%d\n", b[rt+1]);
59 }
60 
61 int main(){
62     scanf("%d", &T);
63     while(T--){
64         scanf("%d%d", &n, &q);
65         //n = read();
66         //q = read();
67         //for(int i = 1; i <= n; i ++) a[i] = b[i] = read();
68         for(int i = 1; i <= n; i ++)scanf("%d", a + i), b[i] = a[i];
69         Build(1, 1, n);
70         sort(b + 1, b + n + 1);
71         sz = unique(b + 1, b + n + 1) - (b + 1);
72         while(q --)work();
73     }
74     return 0;
75 }
View Code

相关文章: