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