2018.3.15校内互测总结-点分治-线段树
這是曾來過咱們學校集訓的一位大神出的~
T1
題目大意
給出一棵帶邊權的無根樹,求樹上前$k$大的路徑的長度。
$1 \leq n \leq 200000$
題解
想了一上午點分治,卻發現只會$O(nlog^3n)$的......
正解是二分第$k$大的權值,用點分治判斷,統計路徑時用兩個指針掃一下權值序列就行了......
這里記錄一種巧妙的,常數更小的方法。
考慮序列求前$k$大路徑的經典操作:
維護一個大根堆,初始將每個左端點和它所能到達的最遠右端點以及距離構成的三元組壓入堆中,按照距離排序。
每次從堆頂彈出一個區間,就把當前左端點的所有右端點中,與當前彈出右端點最接近但是更劣的一個右端點作為該三元組的新右端點,重新計算距離并將三元組壓回堆內,重復$k$次即可取得前$k$大路徑。
現在考慮如何在樹上運用這種操作:
還是考慮點分治,對于每次點分治,找出分治子樹中的每個節點所屬的子樹,及這個點到分治重心的距離,打包成二元組存下來。
可以發現,只有子樹不同的兩個節點構成的路徑才是有效的。因此,對于每個分治重心,將打包好的二元組按距離從大到小排序成一個序列,從后往前預處理出每個二元組向后第一個所屬子樹與當前二元組不同的位置。
將每個二元組與其向后第一個所屬子樹與當前二元組不同的位置處的二元組打包后壓入一個全局堆里,作為一條路徑。
這個堆的功能類似序列版本時的堆,每次彈出堆頂元素后,將這個元素左端點在對應分治重心的序列中,下一個與當前左端點所在子樹不同的二元組作為新的右端點,壓回堆中。
可以發現,對于每個分治重心的每個二元組,最多只有一個對應的二元組在全局堆中,空間復雜度$O(nlogn)$。同時,對于維護最外層的堆,和對二元組序列的排序兩部的復雜度均為$O(nlog^2n)$,因此時間復雜度為$O(nlog^2n)$。
T2
題目大意
維護一個序列,要求支持區間最大值、區間并上一個數、區間或上一個數三種操作。
題解
出于各種原因十天前剛考過原題大家都$A$了這題~
考慮線段樹。
考慮在暴力遞歸到底以修改每個線段樹節點的基礎上添加優化,那么顯然有一個結論:
若一個區間某一位的值全部相同,那么對于這一位來說,接下來進行任何的修改操作,都只需要區間打$tag$,而不用暴力遞歸到底。
具體實現時,只需要維護一下區間或和和區間并和,并判斷一下是否全為$0$或$1$即可。
然后,考慮位運算的結合律:
$(A&B|C)&D=(A&(B&D))|(C&D)$
$(A&B|C)|D=(A&B)|(C|D)$
于是維護區間或標記和區間并標記,下傳時強制先做并再做或。
此時,只要在區間或時,判斷一下修改的值有$1$的位置在當前區間上是否全為$0$或$1$,如果為真則打標記停止遞歸。區間并同理。
復雜度可通過勢能分析證得是$O(nklogn)$。
T3
這是個暫時不會待填的坑~
轉載于:https://www.cnblogs.com/zltttt/p/8577253.html
總結
以上是生活随笔為你收集整理的2018.3.15校内互测总结-点分治-线段树的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微整多少钱啊?
- 下一篇: [UWP小白日记-10]程序启动屏(io