【带修改的主席树】理解题解 (P2617 【Dynamic Rankings】题解)
一:前置芝士:
1.树状数组(不会树状数组来打这个?(大雾 )
2.主席树(不会主席树来打这个?(巨雾 )
3.前缀和 (不会前缀和来打这个?(神雾 )
4.权值线段树 (不会权值线段树来打这个?(仙雾) )
5.看这篇文章的你需要用主席树将求区间kth练得比较熟,并且要理解其原理。
二:分(che)析(dan):
首先,我们知道,主席树其实是一颗具有n个根的树(介于树与森林之间)。第i个根所形成的树(为了简写,我们用T(i)表示)其实就相当于将序列1->i依次添加进一个权值线段树所形成的树。
我们又知道,权值线段树所储存的信息其实是它所管的区间中数字的数量,所以,对于区间l->r所形成的权值线段树,它相当于将T(r)的每一个节点与T(l-1)中对应的节点作差所行成的树。用一句话概括:"对于1->i所形成的树,它是可减的。"这便是主席树的核心内容。
然后,boss来了,如何使主席树资瓷修改操作呢?
暴力的做法:如果我们修改了节点x的值(设为w[x])为y,那么包含节点x的主席树为T(x)->T(n),我们只需要把T(x)->T(n)都去减一个w[x]的值,加一个y。单次复杂度O(nlogn)。于是光荣地超时了QwQ
那么,我们该怎么办呢?
这里给出答案:我们知道,在查询时,我们需要将T(r)-T(l-1),其中T(x)表示的是将1-x序列构成的权值线段树。即是说:T(x)=T(x-1)+w[x] (这里的‘+’代指将w[x]添加到树中)。现在有没有什么感觉?没错!T(x)其实就相当于记录的前缀和(注:此前缀和非彼前缀和)!于是,查询时,我们相当于求1->r,与1->l-1的一个前缀和!
现在,我们简化下题目:给出一个序列,资瓷单点修改和求区间和
看到这里,是不是恍然大悟?这不是sb树状数组(线段树/分块)嘛!
由于树状数组快,又好打,所以我们选择树状数组(抠鼻
没错!其实我们只需要像做树状数组那样,维护这个序列就好了!只需要将每次的O(1)加法替换成O(log n)的修改主席树的add操作即可!复杂度O(nlognlogn)!
撒花!!!
三:实现:
由于某种神奇的玄学原因,我的代码的常数巨大,不适用于各位同学,所以,这里给只出代码。同学们可以自行去网上搜搜模板,看看大佬们的巨快实现!
四:闲话:
讲了这么多,感觉,还是自己讲得自己理解得比较好啊QwQ。我感觉我讲的其实还是挺好的吧?