标签:
先来看下这道线段树的题:CWOJ1197 线段树之查询第k大带修改
有N个箱子,分别放在[1, N]区间的整点上,一个整点上可以有多个箱子。
比如,N = 7 , X = {1, 2, 2, 5, 6, 7, 7},表示1,5,6三个点上分别有一个箱子,2,7两个点上分别有两个箱子
每组数据,首先给出N和X。接下来有三种操作,查询和修改
1. (Q,k):查询[1, N]区间上第k个箱子所在的位置。比如X = {1, 2, 2, 5, 6, 7, 7},(Q,3)= 2,(Q,6) = 7
2. (D,k):删除[1, N]区间上第k个箱子。比如X = {1, 2, 2, 5, 6, 7, 7},执行(D,3)后,X = {1, 2, 5, 6, 7, 7}
3. (A,p):在[1, N]区间上整点p位置放上一个箱子,比如X = {1, 2, 2, 5, 6, 7, 7},执行(A,6)后,X = {1, 2, 2, 5, 6, 6, 7, 7}
给出N次操作,请在每次第1种操作后输出答案
第一行输入一个整数N (1
≤ N≤ 105 )
接下来一行输入N个整 数,X1 ,X2 ,……,XN (保证1≤ Xi ≤ N)
接下来N行输入操作,分别以(Q,k)或(D,k)或(A,p)形式出现,其中(X,Y),X为大写英文字母,Y为整数,保证输入合法
在每次第1种操作后输出答案
7
1 2 2 5 6 7 7
Q 3
Q 7
D 3
Q 6
A 6
A 3
Q 6
2
7
7
6
关键在于Query函数
int Query(int id, int l, int r, int k);
这个函数,返回[1, n]区间中第k个数在哪个位置。我们用线段树的方法,划分每个区间,tree[1].sum表示[1, n]区间有多少个人,tree[2].sum表示[1, n/2]区间有多少个人,tree[3].sum表示[n/2 + 1, n]区间有多少个人…
起初,我们查询Query(1, 1, n, k); 接下来,进行如下判断:if (tree[2].sum >= k) Query(1, 1, n / 2, k); else Query(1, n / 2 + 1, n, k - tree[2].sum);
明白了吗?
对于每个区间,只要它有子区间,就这样子判断。即,如果它左孩子区间的sum不小于当前的k,则往左孩子查,否则往右孩子查,但是k要改为k减去左孩子区间的sum…
当查到一个区间没有子区间时,即其 l 等于 r 时,这个 l 就是要查询的答案,就是[1, n]中第k个数的位置。
okay!只要掌握了这个关键部分,其他操作都可以完成了
有了上题的基础,主席树就很好讲了。主席树,可以处理一个一般的问题,即区间查询第k大。
比如这道题:hdu 3727题目链接
题意是有4种操作
1、在项链后面插入一个珍珠,保证每一个珍珠都不一样
2、查询第 l 到 第 r 个珍珠之间第k大的珍珠的大小
3、假设把所有珍珠按照大小排序,查询size为x的珍珠的排名
4、查询所有珍珠里第k大的珍珠的大小
题目只需要输出2,3,4询问的所有答案即可
第3个询问很简单,不谈。第4个询问本质上和上一道CWOJ的题是一样的。而第2个操作需要用到主席树的思想。
主席树的思想是可持久化线段树,先不要在意这个名字,来看下这个思想的具体内容。
假设我们现在建立n棵线段树T(x)(先不要管空间和时间问题),T(i)记录的是[1, i]区间内的data。比如,我们调用T(10).Query(1, 1, 10, k),就是查询[1, 10]区间当中,排名为k的数所在位置。同样,调用T(4).Query(1, 1, 4, k)就是查询[1, 4]区间但中,排名为k的数所在位置。
主席树的思想满足一个加减性。
还记得在上一道题中,是如何查询第k大的吗?
我们是用到,判断左孩子区间的sum和k的大小,从而判断是往左还是往右孩子区间走,从而找到答案的… 对吧?
这个sum值是数值,是满足加减性的。
那么,现在我们要查询[5, 10]区间中第k大的数,我们只需将sum替换为[1, 10]的sum减去[1, 4]的sum,其他方法和之前一样,就可以查询答案了… 对吧?
也就是说,要查询Query(1, 5, 10, k),只需要用到T[5..10] = T(10) - T(4)的方法,在T[5..10]中查询即可。
假设不考虑空间和时间,每棵线段树都可以建立出来,那么用到这个方法,就可以找到答案。但空间和时间是必须要考虑的,这也是主席树的重点,可以用一种方法,来节省空间和时间,使得空间和时间都是有O(NlogN)级别。
接下来的内容,边上课边完成把。。
标签:
原文地址:http://blog.csdn.net/uestc_peterpan/article/details/51347147