POJ 2104 K-th Number && Luo Gu P3834 [template] can persist tree line 1 (Chairman of the tree)

I was surprised to find two identical questions

Topic background

This is a very classic Chairman tree entry title - still a small section of K

Data has been strengthened, use the chairman trees. Also note that the constant optimization

Title Description

As stated, a given sequence of integers N, K a small value of the query within its specified range for the closed interval.

Input and output formats

Input formats:

 

The first line contains two positive integers N, M, respectively the length and the number of query sequences.

The second line contains N integers, indicates that the sequence number.

Next M lines contains three integers L, R & lt, k L , R & lt , k, indicates that the query interval [L, R & lt] [ L , R & lt k-th smaller value within].

 

Output formats:

 

K comprising the result output lines, each an integer of 1, respectively for each query

 

Sample input and output

Input Sample # 1: 
5 5
25957 6405 15770 26287 26465 
2 2 1
3 4 1
4 5 1
1 2 2
4 4 1
Output Sample # 1: 
6405
15770
26287
25957
26287

Explanation

data range:

For 20% of the data satisfies: . 1 \ Leq N, M \ 10 Leq . 1 N , M . 1 0

For 50% of the data satisfies: . 1 \ Leq N, M \ ^ Leq 10. 3 . 1 N , M . 1 0 . 3

For 80% of the data satisfies: . 1 \ Leq N, M \ ^ Leq 10. 5 . 1 N , M . 1 0 . 5

To 100% of the data satisfies: . 1 \ Leq N, M \ Leq 2 \ ^ CDOT 10. 5 . 1 N , M 2 . 1 0 . 5

For all count column a_i A I , are satisfied - ^ {10}. 9 \ Leq a_i \ Leq ^ {10}. 9 - . 1 0 . 9 A I . 1 0 . 9

Sample Data Description:

N=5,数列长度为5,数列从第一项开始依次为[25957, 6405, 15770, 26287, 26465 ][25957,6405,15770,26287,26465]

第一次查询为[2, 2][2,2]区间内的第一小值,即为6405

第二次查询为[3, 4][3,4]区间内的第一小值,即为15770

第三次查询为[4, 5][4,5]区间内的第一小值,即为26287

第四次查询为[1, 2][1,2]区间内的第二小值,即为25957

第五次查询为[4, 4][4,4]区间内的第一小值,即为26287

解题思路:

定义:主席树是一种可持久化的线段树 又叫函数式线段树

 

刚开始学是不是觉得很蒙逼啊 其实我也是 

主席树说简单了 就是保留你每一步操作完成之后的线段树 然后有可加减性

呃 。。。 这么说好像还是有点生涩

 

 

那么就拿poj2104来举例子吧 慢慢讲我觉得会很好的

题意就是给你一个100000长度的数字 然后100000次询问[L,R]之间第k大的数字是多少

这个很容易看出来 暴力根本不可以 黑你分分钟的事情啊 

我们怎么办呢 想想线段树能不能做 想来想去 一颗线段树好像不能这么做 GG

那么我们做一个美好的假设:

我们建立100000棵美丽的线段树 每一个线段树的节点 表示这一个区间内有多少个数字

 

第一棵线段树保存着把第一个数字插入进去之后 每个区间有多少个数字

第二棵线段树保存着把第一个 第二个数字插入进去之后 每个区间有多少个数字

第n棵线段树保存着把第1,2,3。。。。n个数字插入进去之后 每个区间有多少个数字

 

好了 我们已经建立了这么多的线段树 我们接下来该怎么办呢?

对 就是查询 

可是如何查询呢? 假设我们要查询[l,r]内的第k大

我们可以拿出第l-1 ,r 棵线段树,然后两者相减 我们想一下 这样不就得到了相当于插入了第l到r个点所建立的一棵线段树 这棵线段树每个节点保留的信息是:这个区间内数字的个数 然后我们往下二分查找 就可以得到第k大了

现在的问题时 这么庞大的空间开销我们耗费不起 我们该如何建立这样的线段树呢?

答案就是 我们要尽量利用重复节点 

我们可以想一下 我们每次建立线段树 相对于前一棵线段树 我们只修改了它的一条路径 最多只有logn的变化 那么我们就存下这logn的变化 尽可能的利用重复节点 就可以达到重复使用的目的

//原文:https://blog.csdn.net/qq_34271269/article/details/54849370

AC代码:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #define maxn (int)(1e6+10)
 5 
 6 using namespace std;
 7 
 8 struct kkk {
 9     int cnt,l,r;
10 }t[30*maxn];
11 int init[maxn];
12 int cop[maxn];
13 int tc[maxn];
14 int n,tcnt = 0,newn,m;
15 
16 void Discretization() {//离散化 
17     sort(init,init+n);
18     newn = unique(init,init+n) - init;
19     for(int i = 0;i < n; i++) cop[i] = lower_bound(init,init+n,cop[i]) - init;
20 }
21 
22 int add(int num,int bei,int l,int r) {
23     ++tcnt;
24     t[tcnt].cnt = t[bei].cnt + 1;
25     int save = tcnt;
26     int mid = (l + r) >> 1;
27     if(l == r) {
28         return save;
29     }
30     else if(num <= mid) {
31         t[save].l = add(num,t[bei].l,l,mid);
32         t[save].r = t[bei].r;
33     }
34     else {
35         t[save].r = add(num,t[bei].r,mid + 1,r);
36         t[save].l = t[bei].l;
37     }
38     return save;
39 }
40 
41 int chaxun(int x,int y,int k,int l,int r) {
42     if(l == r) return l;
43     int p = t[t[y].l].cnt - t[t[x].l].cnt;
44     int mid = (l + r) >> 1;
45     if(k <= p) 
46         return chaxun(t[x].l,t[y].l,k,l,mid);
47     else 
48         return chaxun(t[x].r,t[y].r,k-p,mid + 1,r);
49 }
50 
51 int main()
52 {
53     scanf("%d%d",&n,&m);
54     for(int i = 0;i < n; i++) {
55         scanf("%d",&init[i]);
56         cop[i] = init[i];
57     }
58     Discretization();
59     for(int i = 1;i <= n; i++) {
60         int p = add(cop[i-1],tc[i-1],0,n);
61         tc[i] = p;
62     }
63     for(int i = 0;i < m; i++) {
64         int x,y,k;
65         scanf("%d%d%d",&x,&y,&k);
66         int ans = chaxun(tc[x-1],tc[y],k,0,n);
67         printf("%d\n",init[ans]);
68     }
69     return 0;
70 }

 

Guess you like

Origin www.cnblogs.com/lipeiyi520/p/10991241.html