First, the President of the trees and the weight difference between the tree line
Chairman of the tree is composed of many tree line weights, individual weights segment tree can only be solved to find the entire range of k large / small-value problem (what is the whole interval, such as you interval [1,8] to establish a corresponding weight value segment tree, then you can not ask the interval [2,5] k-large / small value, you can only ask [1,8] k-big / small-value problem)
Second, what is the right value segment tree ghost
Before learning segment tree weights you certainly want to know that tree line, tree line is the number of all sections of maintenance
Weight segment tree maintenance object and its different weights <==> the number of times this number appears in this interval
For example 1,5,3,2,4
The right to establish the value of the tree line:
You will find that the weight of the tree line and the establishment of different tree line, tree line to consider the position of each number in the interval
But the tree line do not control the weight, the equivalent of a tree after drained established order. To note: the weights on behalf of this number there have been several
For example: We are looking for the third small interval of values
We judge from the root [1,5] of the left node, because the weight of the left node is greater than 3, so the first 3 small value within the interval certainly at the root node in the left section
We look at the interval [1,3] of the left node, found that it is the right of the left node 2 is less than 3, so the answer is certainly in the interval [1,3] to the right node. Note: this time we are looking for 3-2 small value in the right node
After that first small range of values [3,3] 3 itself it is certainly within the
If you pay attention to the topic of data is particularly large, such as 1,1000,200000000 these three numbers, but if we built directly weights tree line, that memory on the bombing
So this time we should discretization
Third, the President of the trees make
We said at the beginning of the article, the Chairman of the tree is composed of many weights tree line, and Chairman of the tree can be resolved: the corresponding interval established by the President tree, you can find the k large / small values within the interval of all sub-sections
(Ie, the interval [1,5] Chairman established tree, then we can look for the interval [1,3] k-large / small value)
1, Resolution 1:
After sorting to find the location of the output (do not want a violent methods will certainly be card)
2. Solution 2:
For an interval [l, r] we appeared with a number within this range with the composition of a number of weights tree line, then the query gets the job done
But repeatedly asked a small range of k, so every time we build a tree line, so that not only the spatial complexity is very high, and the time complexity is very high, even higher than the ordinary sort, then we just can not think of a way, such that for each of us for different intervals we do not need to re-contribution, if so. Time complexity and space complexity is greatly reduced.
3. Solution 3:
This uses prefixes and , for example, we have a problem. Each time interval is static and seek, so we can pre-prefix and the sum [i], every time we solve the interval [l, r] and when we can get the answer directly to sum [r] - sum [l - 1], so that no number for each interval are summed to solved. (Here we set SUM [i] is the weight of the discharge line weights tree node i)
Expect to write up
We can interval [1,5] Create segment tree weights 6, namely, [0,0], [1,1], [1,2], [1,3], [1,4], [ 1,5] ([0,0] is an empty tree)
We will deal with an arbitrary interval [l, r] can pass when the processing interval [1, l - 1], [1, r], on the line, and then processing results are summed two line subtraction. Why meet nature of addition and subtraction, we can easily draw a simple analysis. If [1, l - 1] x in the interval with a number less than a number, in [1, r] y is less than the number that has a number, then in the interval [l, r] y in there - the number of x less than that number, so you can well understand why the addition and subtraction, addition, and every single tree structure are the same, is a leaf node is n the tree line.
Above using the prefix and the idea is just to solve the problem of the complexity of the time, it does not solve the problem of space complexity, space complexity to solve the problem. We need to use the property line of the tree, every time we update a number, then compared with the previous update, the Fengyun tree line change just one chain (from the root node to a leaf node), then we can take advantage of this feature, because of the tree than the first particles i i- 1 pieces tree, simply updates the i th element, then the particles in fact, between the i and i-1 th tree tree particles only log node information is different. So the two trees have a lot of the same node, the two trees may share many nodes, i.e., a node we insert a [i] in the i-1 th tree obtained i-th particle weight particle segment tree , and a single point of insertion process only modifies that log on the root node to the leaf nodes of the path. So this would resolve the problem of the space complex.
1,3,2,5,4 or in the above as an example:
1, the beginning of an empty tree
2, node 1 plus a
3, plus a 2 node
4, adding a node 3
Behind No. 4 and 5 nodes do not write, you know on the line. . .
Fourth, the President of the complexity of the tree
Insert a point in space and time complexity are O (log n), so the establishment of the President of the Fengyun tree tree line [weight] of the overall complexity of time and space is O (n log n), a single inquiry after log n nodes, time complexity is also O (log n)
5, example
K-th Number POJ - 2104
Code 1:
1 #include<stdio.h> 2 #include<iostream> 3 #include<algorithm> 4 #include<string.h> 5 using namespace std; 6 const int maxn=1e5+10; 7 int cnt,ranks[maxn],v[maxn],root[maxn]; 8 struct shudui 9 { 10 int value,id; 11 }w[maxn]; 12 struct Node 13 { 14 int l,r,sum; 15 Node(){ 16 sum=0; 17 } 18 }tree[maxn*20]; 19 bool mmp(shudui x,shudui y) 20 { 21 return x.value<y.value; 22 } 23 void init() 24 { 25 cnt=1; 26 root[0]=0; 27 tree[0].l=tree[0].r=tree[0].sum=0; 28 } 29 void inserts(int num,int &rt,int l,int r) 30 { 31 tree[cnt++]=tree[rt]; 32 rt=cnt-1; 33 tree[rt].sum++; 34 if(l==r) return; 35 int mid=(l+r)>>1; 36 if(num<=mid) inserts(num,tree[rt].l,l,mid); 37 else inserts(num,tree[rt].r,mid+1,r); 38 } 39 int query(int i,int j,int k,int l,int r) 40 { 41 int d=tree[tree[j].l].sum-tree[tree[i].l].sum; 42 if(l==r) return l; 43 int mid=(l+r)>>1; 44 if(k <= d) return query(tree[i].l, tree[j].l, k, l, mid); //这里是小写的L,mid可不是数字1 45 else return query(tree[i].r, tree[j].r, k - d, mid + 1, r); 46 } 47 int main() 48 { 49 int n,m; 50 scanf("%d%d",&n,&m); 51 for(int i=1;i<=n;++i) 52 { 53 scanf("%d",&w[i].value); 54 w[i].id=i; 55 } 56 sort(w+1,w+1+n,mmp); 57 w[0].value=-1; 58 int j=1; 59 for(int i=1;i<=n;++i) 60 { 61 if(w[i].value!=w[i-1].value) 62 ranks[w[i].id]=j,v[j]=w[i].value,j++; 63 else ranks[w[i].id]=j-1; 64 } 65 init(); 66 for(int i=1;i<=n;++i) 67 { 68 //printf("%d %d\n",ranks[i],v[i]); 69 root[i]=root[i-1]; 70 inserts(ranks[i],root[i],1,n); 71 } 72 while(m--) 73 { 74 int l,r,x; 75 scanf("%d%d%d",&l,&r,&x); 76 printf("%d\n",v[query(root[l-1],root[r],x,1,n)]); 77 } 78 return 0; 79 }
代码2:
1 //洛谷 P3834 可持久化线段树(主席树) 2 3 #include<cstdio> 4 5 #include<cstring> 6 7 #include<algorithm> 8 9 using namespace std; 10 11 const int N=200005; 12 13 int n,m,q,t=0; 14 15 int a[N],b[N],root[N]; 16 17 struct node 18 19 { 20 21 int ls,rs,sum; 22 23 }tree[N*20]; 24 25 void disc() 26 27 { 28 29 int i; 30 31 sort(b+1,b+n+1); 32 33 m=unique(b+1,b+n+1)-(b+1); 34 35 for(i=1;i<=n;++i) 36 37 a[i]=lower_bound(b+1,b+m+1,a[i])-b; 38 39 } 40 41 42 43 //insert函数就是说:当前插入的数p,会影响节点x,所以把x节点的sum加1. 44 45 46 47 //节点x代表一个权值区间,影响x就是说p在节点x所代表的权值区间内。 48 49 //那么先把前一个树的对应区间的节点复制过来,再加1,就行了。 50 51 //可以结合刚才的图感性理解一下。 52 53 void insert(int y,int &x,int l,int r,int p) 54 55 { 56 57 x=++t; //t相当于是一个节点的地址,每个节点是不同的。 58 59 tree[x]=tree[y]; //复制前一个树的对应节点【它们代表的权值区间相同】。 60 61 tree[x].sum++; //给这个节点的sum加1.(这个1指的就是p) 62 63 if(l==r) return; //搜索到根节点就返回。 64 65 int mid=(l+r)>>1; 66 67 68 69 //判断在哪个区间继续插入。 70 71 if(p<=mid) insert(tree[y].ls,tree[x].ls,l,mid,p); 72 73 else insert(tree[y].rs,tree[x].rs,mid+1,r,p); 74 75 } 76 77 78 79 //k是查询第k小 80 81 //x和y相当于是树的节点的地址。而l和r就是这两个节点的权值区间。 82 83 //一开始query(root[l-1],root[r],1,m,k)。 84 85 //root[l-1]就是第l-1颗树的根节点。root[r]就是第r颗树的根节点。 86 87 //比较它们左儿子代表的区间中的数的个数,差值为delta。根据delta判断这两个节点一起往哪个方向跳。 88 89 //分析过程和刚才二分的过程一样。 90 91 int query(int x,int y,int l,int r,int k) 92 93 { 94 95 if(l==r) return l; //查到权值线段树的叶子节点就返回这个值。 96 97 int delta=tree[tree[y].ls].sum-tree[tree[x].ls].sum; 98 99 int mid=(l+r)>>1; 100 101 if(k<=delta) return query(tree[x].ls,tree[y].ls,l,mid,k); 102 103 else return query(tree[x].rs,tree[y].rs,mid+1,r,k-delta); 104 105 } 106 107 int main() 108 109 { 110 111 int l,r,i,k; 112 113 scanf("%d%d",&n,&q); 114 115 for(i=1;i<=n;++i) 116 117 { 118 119 scanf("%d",&a[i]); 120 121 b[i]=a[i]; 122 123 } 124 125 disc(); 126 127 for(i=1;i<=n;++i) 128 129 insert(root[i-1],root[i],1,m,a[i]); 130 131 for(i=1;i<=q;++i) 132 133 { 134 135 scanf("%d%d%d",&l,&r,&k); 136 137 138 139 //query函数返回的是第k小的权值。 140 141 //把这个权值转化为原来这个权值对应的数就行了。 142 143 printf("%d\n",b[query(root[l-1],root[r],1,m,k)]); 144 145 } 146 147 return 0; 148 149 }
参考博客:
https://blog.csdn.net/g21glf/article/details/82986968
https://blog.csdn.net/creatorx/article/details/75446472