【做題記錄】ds合集 Part I

FantasyNumber發表於2024-10-18

ds 合集的 Part 1,此合集包含樹上問題和圖上問題。

樹上問題

CF418D

題目連結

首先可以倍增找到 \((u,v)\) 中間的斷點 \(t\)\(t\) 和左邊都去 \(u\),右邊都去 \(v\))。然後就可以把樹分成兩部分(這裡注意如果 \(t=lca(u,v)\) 不能直接取子樹),然後就是求 \(\max(dis(u,S1),dis(v,S2))\)。問題就是點到一個聯通塊的距離,且這個聯通塊是一個完整子樹或樹減去子樹,在 dfn 序上至多分成兩個區間。這個問題就隨便做了,可以離線下來樹上掃描線,也可以直接在 dfn 序上合併直徑(最大距離一定是到直徑兩端點之一),或者樹剖維護都可以。複雜度 \(\Theta(n\log n)\)

CF741D

題目連結

其實就是求經過每個節點 \(u\) 且兩端在 \(u\) 子樹中的最長合法路徑。一個路徑合法當且僅當不超過一個字元出現奇數次,考慮將出現次數的奇偶性狀壓,那麼就是找 \(u\) 中兩個不同子樹的點對,滿足它們到根的路徑狀態異或和的大小不超過 \(1\),記錄一下每個點的深度和狀態,列舉奇數的位置就行,dsu on tree 處理,開個桶記錄 \(2^{22}\) 個狀態就行。複雜度 \(\Theta(nc\log n)\)​。

CF763D

題目連結

不同構肯定樹 hash,考慮樹上掃描線,維護所有子樹的 hash 值的桶。每次根從 \(u\) 轉移到 \(v\) 時,會刪掉以 \(u\) 為根的整棵樹,加入以 \(v\) 為根的整棵樹,加入以 \(u\) 為根除了 \(v\) 子樹以外的樹。map 記錄出現次數就行,複雜度 \(\Theta(n\log n)\)

CF776F

題目連結

考慮這些區域會形成一棵樹,可以暴力處理一下編號。然後就是在一棵樹上染色,考慮從小往大染色。顏色是 \(1\) 的顯然只有一個點 \(u\),那麼顏色是 \(2\) 的點在 \(u\) 的所有子樹中都不能超過一個,顏色為 \(3\) 的點可以在顏色 \(2\)\(u\) 的路徑上,也可以在顏色 \(2\) 的子樹中。發現這個東西很像點分治的形式,於是模仿點分治,將每層都染成同一個顏色,個數不超過 \(\Theta(\log n)\)。複雜度 \(\Theta(n\log n)\)

CF925E

題目連結

假設樹上每個點的權值是 \(a_i\),初始 \(a_i = t_i\)。那麼變成黑點相當於鏈減 \(1\),變白點相當於鏈加 \(1\)。現在就是要支援:區間加減 \(1\),單點標記,詢問全域性沒標記的點小於 \(0\) 的個數。這個可以分塊 \(\Theta(n\sqrt{n} \log n)\) 做,空間 \(\Theta(n\sqrt{n})\) 類似 這題。但是考慮 \(\Theta(n\sqrt{n})\) 的做法,空間線性。直接對詢問分塊,考慮將每 \(B\) 個詢問一起做,那麼記錄每個點在前面處理完之後的權值 \(a_i\),然後考慮這 \(\Theta(B)\) 個點的貢獻。將這 \(\Theta(B)\) 個點建虛樹,每條邊加的值都相等,那麼將每個點都掛到它所在的虛邊的深度大的那個點上然後排序,然後每次鏈加可以暴力跳祖先 \(\Theta(B)\) 個點,然後再對每條虛邊記錄指標 \(pos_i\) 為當前第一個 \(<0\) 的位置,每次加會使指標移動 \(\Theta(1)\) 個位置(因為只會 +1 或 -1)。排序部分可以把 \(n\) 個點放到一起基數排序,然後複雜度就是 \(\Theta(n\sqrt{n})\) 了。

CF833D

題目連結

路徑數數考慮點分治,那麼就是要考慮一堆三元組 \((val,x,y)\) 表示路徑的權值積,黑色點 \(x\) 個,白色點 \(y\) 個。那麼就是要找一堆三元組對,\((val1,x,y),(val2,a,b)\) 滿足 \(\dfrac{1}{2} \le \dfrac{a+x}{b+y} \le 2\),化簡一下就是

\[\left\{ \begin{array}{**lr**} 2a-b\ge y-2x \\ 2b-a\ge x-2y \end{array} \right. \]

\(x_i = 2a-b,y_i = 2b-a\) 為詢問點,\(x_i = b-2a,y_i = a-2b\) 為插入點,那麼就是要對每個詢問點找到所有 \(x_j \le x_i,y_j \le y_i\) 的乘積,可以簡單二維數點。那複雜度就是 \(\Theta(n\log^2 n)\),但是直接搞會算兩次,就成平方了,然後可以寫個 cdq 三隻 \(\log n\),還是能過。

CF986E

題目連結

把每個數的所有質因子找出來,然後對每種質因子用動態開點線段樹維護,然後詢問列舉 \(w\) 的因子搞,暴力這樣做是 \(\Theta(n\log^2 n \log V)\) 的,無法透過。發現不用樹剖,其實就是要求 \(\Theta(n\log V)\) 次一個點到根上含有 \(p\) 質因子的有多少個。考慮離線,考慮對每個質因子單獨處理,把 \(w\) 的所有質因子 \(p\) 處掛 \(u,v,lca(u,v),fa(lca(u,v))\) 四個詢問,然後把所有含有 \(w\) 質因子的點拿出來,子樹加,單點查即可。複雜度 \(\Theta(n\log n \log V)\)

CF983E

題目連結

先考慮每個詢問暴力做,發現把 \((u,v)\) 的路徑拿出來,一定是先坐一個能走最長的車,再換乘,直到走到 \(v\)。如果 \(v\)\(u\) 的祖先肯定很好做,就是從每個點往上一直走,首先預處理從每個點往上坐 \(1\) 條線走到最遠哪裡,這個可以把每個路徑的 \(u,v\) 處插入一個插入標記,在 \(lca(u,v)\) 插入一個刪除標記,然後直接線段樹合併就能做到單 \(\log\)。然後就是倍增處理走 \(2^i\) 步最淺到哪,兩邊同時跳到 \(lca\) 下面的點,然後看看是否有路徑在 \((u',v')\) 子樹中,就是個二維數點,主席樹線段樹合併隨便做就行。複雜度 \(\Theta(n\log n)\)

CF1039D

題目連結

注意到路徑不能重複,所以考慮根號分治。當 \(k \le B\) 時,考慮單次暴力,設二元組 \(f_u\)\(u\) 的子樹中能選出多少條長度 \(k\) 路徑,且滿足第一關鍵字的情況下能有最多多少從根往下的空白。顯然 \(\Theta(n)\) 做即可,複雜度 \(\Theta(nB)\)。當 \(k > B\) 時,此時答案不超過 \(\dfrac{n}{B}\),且答案有單調性,所以考慮對於每個答案,二分它的邊界,用上面的方法暴力驗證,複雜度 \(\Theta(\dfrac{n^2 \log n}{B})\)。當 \(B\)\(\sqrt{n\log n}\) 時,有最優複雜度 \(\Theta(n \sqrt{n\log n})\)

CF1083C

題目連結

考慮從 \(mex\) 入手,怎麼判斷權值為 \([0,i]\) 的區間是否組成一個鏈。判斷若干個點是否組成一條鏈當然可以使用線段樹來合併,把左右兒子組成的鏈的 \(4\) 個點拿出來,列舉這個新鏈的兩個端點,判斷其他兩個點是否在這條鏈上(就是 \(dis(x,u)+dis(x,v)=dis(u,v)\))就行,然後再套個線段樹二分,複雜度 \(\Theta(n\log n)\)

CF1088F

題目連結

首先感覺一下,發現重構出來的樹以最小權值作為根時,也應該是父親權值小於兒子的。因為如果父親權值大於兒子,那麼我可以找到深度最大的這樣的點,刪掉這個點和它父親的連邊,把它接到原本樹上的父親上(由於這個深度是最大的,所以子樹肯定沒有它原本樹上的父親),透過這樣的調整一定更優,於是就可以調整成一個父親權值小於兒子的了。那麼就是考慮連到比它小的點,如果連到一個不是祖先的點,那麼找到這個點和它的 \(lca\),這個 \(lca\) 的權值比它們都小,而且距離更近,所以肯定更優。那麼就是在原樹上找到一個祖先連邊了,直接列舉 \(\lceil \log_2 dis(u,v)\rceil\),把 \(u\) 到根的鏈分成 \(\Theta(\log n)\) 段,然後在每個段上找到一個最小值連就行,其實就是這個段最頂上那個點,就是 \(u\)\(2^k\) 祖先(注意一下邊界),權值是 \(a_u + \min a_v (1+k)\)。倍增處理即可,複雜度 \(\Theta(n\log n)\)

P2056

題目連結

每個點點權 \(\in \set{0,1}\),每次翻轉單點,求兩個 \(0\) 的距離最大。

  • 最大距離考慮直徑,線段樹維護每個區間的直徑,由於邊權非負,可以貪心合併。(大區間的直徑端點一定在左右兒子的 \(4\) 個端點中取)複雜度 \(\Theta(n\log n)\)不支援負邊權
  • 動態查詢路徑考慮動態點分治,用堆維護每個點 \(u\) 子樹(點分樹)中到父親(點分樹)的所有距離 \(q_u\),用堆 \(son_u\) 維護 \(u\) 到所有兒子(點分樹)的距離(這是將每個 \(q_v\) 中最大的放進來,每個子樹只放一個),再用一個全域性的堆 \(st\) 維護所有 \(son_u\) 最大和次大的和。注意堆要支援刪除,就對每個堆再開一個刪除的堆(把刪除的東西放入),取出時若兩個堆頂相同就同時彈出。修改先刪 \(q\),然後更新 \(son_{fa}\),然後再更新 \(st\)。複雜度 \(\Theta(n\log ^ 2 n)\)​,支援負邊權
  • 最大距離考慮括號序列,dfs 進入一個點塞 \((\),然後塞點編號,然後出來的時候塞 \()\)。顯然兩點距離就是刪除匹配的後 \()))(((\) 的長度。考慮線段樹維護每個點的 \(r_u,l_u\) 表示刪除匹配後這段區間的右括號、左括號個數,和最長長度 \(dis\)。轉移如下
    • \(r_u = r_{ls} + \max(0,r_{rs} - l_{ls}),l_u = l_{rs} + \max(0,l_{ls} - r_{rs})\)
    • $dis_u = \max(dis_{ls},dis_{rs},\max\limits_{i\le mid <j} r_{[i,mid]} + |l_{[i,mid]}-r_{[mid+1,j]}|+l_{[mid+1,j]}) $
      • \(\max\limits_{i\le mid <j} r_{[i,mid]} + |l_{[i,mid]}-r_{[mid+1,j]}|+l_{[mid+1,j]} =\max((l_{[i,mid]}+r_{[i,mid]})+(l_{[mid+1,j]} - r_{[mid+1,j]}),(l_{[mid+1,j]}+r_{[mid+1,j]})-(l_{[i,mid]} - r_{[i,mid]}))\)
    • \(addp_u = \max l_{[l,i]}+r_{[l,i]}=\max(addp_{ls},\max(r_{ls}+l_{ls}+subp_{rs},r_{ls}-l_{ls}+addp_{rs}))\)
    • \(adds_u = \max l_{[i,r]}+r_{[i,r]} = \max(adds_{rs},\max(l_{rs}+r_{rs}-subp_{ls},l_{rs} - r_{rs}+adds_{ls}))\)
    • \(subp_u = \max l_{[l,i]} - r_{[l,i]} = \max(subp_{ls},l_{ls} -r_{ls}+subp_{rs})\)
    • \(subs_u = \max l_{[i,r]} - r_{[i,r]} = \max(subs_{rs},l_{rs} - r_{rs}+subs_{ls})\)
    • 複雜度 \(\Theta(n\log n)\)不支援負邊權

CF1413F

題目連結

記錄 \(sum_i\)\(i\) 到根的邊權異或和,那麼就是要找到兩個點使得它們 \(sum_u = sum_v\)\(dis(u,v)\) 最大,且支援區間翻轉。考慮用 P2056 直徑的思路記錄線段樹每個節點 \(sum=0/1\) 的直徑,翻轉的時候交換一下 \(tr_{u,0},tr_{u,1}\) 即可。複雜度 \(\Theta(n\log n)\)

CF1479D

題目連結

路徑數顏色,考慮主席樹記錄每個點到根的每個顏色出現次數模 \(2\)。如果出現了偶數次就是根到 \(u\) 和根到 \(v\) 的次數模 \(2\) 異或起來是 \(0\)。可以考慮在主席樹上二分找這個 \(x\),那麼就是要快速判斷一段區間的顏色是否按位異或起來都是 \(0\)。用個異或雜湊刻畫這個東西就行了。複雜度 \(\Theta(n \log n)\)

BZOJ3252

題目連結

先考慮一個一個取是不是對的。顯然是對的,因為如果一條路徑在前兩次沒被選而被第一次選了,那麼第一次肯定可以拿第二次的更優,矛盾了。那麼再考慮貢獻不能重複算怎麼辦,設 \(maxn_u\) 為從 \(u\)\(u\) 子樹的一個葉子最長的一條路徑(也就是長鏈),那麼當 \(u\) 子樹裡有被選的點時,\(maxn_u\) 一定被選了,而且是第一次選 \(u\) 子樹內的點時就被選了,所以其他點不可能有 \(u \to maxn_u\) 這條鏈上的貢獻了。那麼一個葉子的貢獻就是它到它所在長鏈鏈頂的權值和,選出前 \(k\) 大的即可,複雜度 \(\Theta(n\log n)\)

CF526G

題目連結

這題是真牛。

考慮單次詢問,那麼把 \(x\) 設為根,顯然這 \(y\) 條路徑都是 \(y\) 對葉子節點構成的,那麼再考慮任意 \(2k\) 個葉子是否存在一個構造使得能覆蓋它們的虛樹呢?答案是肯定的。把它們按照 dfn 序排序,每次把首尾配對即可。那麼不考慮包含 \(x\),就是要求選 \(2k\) 個葉子使得它們構成的虛樹權值和最大,這裡可以運用 BZOJ3252 的長鏈剖分的做法 \(\Theta(n)\) 做,然後如果不包含 \(x\),即它們都在 \(x\) 的同一棵子樹裡,那麼刪掉貢獻最小的那個點,加上 \(x\) 其他子樹到它距離最大的那個就好了 。這樣單次詢問就可以在 \(\Theta(n)\) 的複雜度內搞定。

考慮多次詢問,每次詢問的瓶頸在於每次都要長剖一次,很劣。我們發現每次距離 \(x\) 最遠的那個點,也就是直徑的端點,一定會被選。所以,不妨把直徑的兩個端點分別作為根求答案取最大值。再額外選 \(2y-1\) 個葉子,可以預處理出來選前 \(i\) 個葉子的答案,與 BZOJ3252 一模一樣。然後不包含 \(x\) 的話證明 \(x\) 所在長鏈一定不是前 \(2y-1\) 個,所以可以刪掉第 \(2y-1\) 個換成 \(x\) 的長鏈能讓損失最小。但是考慮 \(x\) 往上第一個遇到的長鏈,若把它去掉,\(x\) 的長鏈還會額外貢獻那條長鏈在 \(x\) 到根這部分的長度,可能更優。所以再判斷刪除第 \(2y-1\) 條鏈和 \(x\) 往上第一條長鏈哪個更優就行。後者可以倍增找到,記錄每個點被覆蓋長鏈的排名就行。複雜度 \(\Theta(n\log n)\)

CF1633F

題目連結

考慮有完美匹配的充要條件,就是 \(\sum\limits_u [2 | siz_u] = \sum\limits_u [2 \nmid siz_u]\),且只會選擇每個 \(2\nmid siz_u\)\((u,fa_u)\) 這些邊。每次加入一個相當於把它到 \(1\) 的路徑上全部翻轉奇偶性,用線段樹維護每個區間的奇數、偶數 \(siz_u\) 個數和每個奇數的 \(siz_u\)\(id(u,fa_u)\) 之和,每次翻轉直接交換奇偶即可,樹剖維護一下,複雜度 \(\Theta(n\log^2 n)\)

CF1654G

題目連結

貪心地走,一定是走到一個點 \(v\) 使得 \(v\) 有相鄰同高度的點,然後反覆跳再下去,就是 \(2h_u - h_v\)。那麼要最小化 \(h_v\)。考慮這樣的 \(v\) 的種類數量,因為每當出現一個兩個高度為 \(t\) 的相鄰的點,就一定底下會多出來 \(2t\) 個點,注意到是樹形結構,所以 \(\sum h_v = \Theta(n)\) 的。那麼 \(h_v\) 就有 \(\Theta(\sqrt{n})\) 種,設 \(f_{i,j}\) 是從 \(i\) 開始走到一個高度為 \(j\)\(v\) 所需要初始最小動能。先從低往高轉移,然後每個相同高度的聯通塊換根轉移。複雜度 \(\Theta(n\sqrt{n})\)

CF1749F

題目連結

考慮到 \(d\) 很小,不妨將所有更改掛到對應節點上,然後列舉查詢節點的不高於 \(d\) 級祖先。

更改時,先考慮 \(lca(u,v)\) 子樹內的貢獻。可以開 \(20\) 棵線段樹維護每個距離的標記。對於鏈 \((u,v)\),可以在這條路徑上每個點在 \([1,d]\) 這些線段樹上加上 \(k\),但是這樣會算重,具體地,對於一個點 \(x\),若它還有兒子 \(y\) 被更改,那麼 \(y\) 子樹中距離 \(y\) 不超過 \(d-1\) 的點會被多加 \(k\)。所以對於鏈 \((u,v)\) 上除了 \(lca(u,v)\) 的點之外所有點都在 \([1,d-1]\) 這些線段樹上減 \(k\)。查詢的時候列舉 \(u\)\(20\) 個祖先然後單點查詢。這樣複雜度是 \(\Theta(nd\log^2 n+nd\log n)\),不平衡。注意到只是單點查,那麼樹上差分一下變成子樹查詢即可,複雜度 \(\Theta(nd \log n)\)。然後是 \(lca(u,v)\) 子樹以外的貢獻,那麼考慮直接列舉 \(lca(u,v)\) 的不超過 \(d\) 級祖先,在每個這樣的點 \(x\)\(20\) 個標記,表示 \(x\) 子樹到 \(x\) 距離等於 \(i\) 的標記。類似地,每次把 \(tag_{x,0}\)\(tag_{x,d-dis(u,lca(u,v))}\) 加上 \(k\),設 \(x\)\(lca(u,v)\) 方向兒子為 \(y\),把 \(tag_{y,0}\)\(tag_{y,d-dis(u,lca(u,v))}\) 全部減去 \(k\) 即可。複雜度 \(\Theta(nd^2)\)(當然可以做到 \(\Theta(nd\log d)\))。

查詢直接列舉 \(u\)\(20\) 個祖先,然後子樹求和就行,再加上標記,複雜度 \(\Theta(n(d\log n+d))\)

所以總複雜度為 \(\Theta(nd(\log n + d))\)

CF1810F

題目連結

注意到答案應該不會超過 \(\max a_i +\log_m{n}\),因為可以構造一個完全 \(m\) 叉樹。於是考慮列舉答案,然後來驗證。設當前答案為 \(ans\),顯然先搞出來個深度為 \(ans\) 的滿 \(m\) 叉樹比較優,然後從後往前列舉值域 \(i\),設當前空位為 \(x\),每次使得 \(x \leftarrow m(x - cnt_i),i\leftarrow i - 1\)。若 \(x\) 始終 \(\ge 0\),那麼就可行。考慮線段樹維護這個東西,設每個區間要合法初始值最小為 \(f_u\),使用最小初始值最後剩下 \(g_u\),從 \(l\) 到第一個有數值的位置設為 \(tr_u\)。合併的時候若 \(m^{len_{ls} - tr_{ls}}g_{rs} \ge f_{ls}\),那麼 \(f_u = f_{rs},g_u = g_{ls}+m^{len_{ls}}(g_{rs} - f_{ls})\)。否則設 \(t=\lceil \dfrac{f_{ls}-m^{len_{ls} - tr_{ls}}g_{rs}}{m^{len_{ls} - tr_{ls}+tr_{rs}}} \rceil\),那麼 \(f_u = t+f_{rs},g_u = g_{ls} + m^{tr_{ls}}(g_{rs}+t\cdot m^{len_{ls} - tr_{ls}+tr_{rs}}- f_{ls})\)。每次單點改即可,複雜度 \(\Theta(n\log n)\)

CF1827D

題目連結

注意到有兩個重心當且僅當存在一條邊使得兩個端點的子樹 \(siz\) 相等且等於 \(\dfrac{n}{2}\)。如果直接維護就是要維護 \(\min |n-2siz_i|\),還要區間加 \(1\)\(1\),比較麻煩。考慮這個點會在哪,感受一下發現肯定是在已經有的重心旁邊,那麼答案就是 \(n-2maxson\),再更新一下重心就行(只會移動一步)。直接樹剖維護,複雜度是 \(\Theta(n\log^2 n)\)

但是可以單 \(\log\),具體地,設重心在 \(x\)\(maxson=k\)\(id\)\(k\) 的編號。若加的是 \(id\) 的子樹裡的點,判斷 \(id\) 是否能成為重心,如果可以 \(id' \leftarrow x,k\leftarrow \dfrac{n}{2},x\leftarrow id\),不然就是 \(k \leftarrow k+1\)。如果不在 \(id\) 子樹判斷這個子樹是否比 \(id\) 子樹更大,更新一下就行。用樹狀陣列維護單點加,區間和,複雜度 \(\Theta(n\log n)\)

CF1904F

題目連結

注意到每個點點值不同,那麼把小的連到大的,要求是個 dag 就行。用線段樹最佳化建圖,複雜度 \(\Theta(n \log^2 n)\)

CF1935F

題目連結

顯然每次連邊只可能是 \((x,x+1)\),且最多隻有一次是 \((x,x+2)\)​。那麼對於每個 \((x,x+1)\),當前僅當它們在一個點的兩個不同子樹中時有用,於是把 \((x,x+1)\) 掛到 \(lca(x,x+1)\) 上,每次用並查集合並。然後子樹的父親的可以記錄每個 \(sum_u\)\(u\) 子樹中最淺的 \(lca(x,x+1)\),如果 \(u\) 的兒子 \(v\)\(sum_v\) 深度比 \(u\) 淺就可以連,然後如果還不聯通的話就要連 \((u-1,u+1)\)。複雜度 \(\Theta(n\log n)\)

CF1976F

題目連結

經典題。考慮根度數是 \(1\),所以第一次肯定是選從根開始的一條路徑,那肯定就是最深的那個葉子。然後第二次就可以選兩個到根的鏈,也一定是兩個葉子(選兩個原因:有個經典結論是在樹上選 \(2k\) 個點一定存在 \(k\) 條鏈並集是它們的虛樹),這個就是 BZOJ3252,長剖之後每個葉子的權值就是它到鏈頭的長度,排個序就好了。複雜度 \(\Theta(n\log n)\)​,瓶頸在排序。

圖上問題

CF280D

題目連結

\(k\) 個可以描述為一個費用流模型,可以模擬費用流來做,但我不會。注意到它是凸的,所以線段樹維護 \(k\) 大子段和,可以閔可夫斯基和合並。複雜度 \(\Theta(nk\log n)\),有 \(16\)​ 倍常數。

沒過

CF757F

題目連結

\(s\) 為起點求一遍最短路,把所有 \(dis(v) = dis(u)+w\)有向邊 \((u,v,w)\) 保留,形成一個 dag。也就是要問這個 dag 上刪掉一個點使得最多有多少與 \(s\) 不連通的點。那就是求新圖上起點為 \(s\) 的支配樹上除了 \(s\) 的最大 \(siz\) 是多少,直接建支配樹求即可。複雜度 \(\Theta(n\log n)\)

CF878C

題目連結

單次可以對每個專案排序,然後每個人連到第一個小於它的人,答案就是縮點之後每個入度為 \(0\) 的 scc 的點數和。這個圖還有個性質,就是它是一個鏈狀物,一個點只可能連到鏈後面的點。所以加邊的時候只有返祖邊會寄。於是先按第一個專案把這條鏈求出來,加邊的時候如果遇到返祖邊就直接用個並查集把之間的點並起來。複雜度 \(\Theta(nk\log n)\),用 set 維護。

CF811E

題目連結

因為一列是完整的,所以考慮用線段樹維護維護兩端的每個點所在的聯通塊編號。合併的時候先把中間的兩列合併,然後再看左右兩邊是否有聯通塊被中間合併的時候一起合併了,並查集維護即可。

CF903G

題目連結

最大流=最小割。為了方便,設 \(A_0 \to A_1,A_n \to A_{n+1}, w=0\)\(B\) 同理 注意到切在 \(A,B\) 的邊分別恰好割一條,設它們分別是 \(x,y\)。那麼要付出的代價就是 \(a_x+b_y + \sum\limits_{u_i \le x,v_i >y} w_i\)。因為只有 \(a_x\) 會改變,不妨先處理出來 \(f_i = \min\limits_j b_j + \sum\limits_{u_k \le i, v_k > j} w_k\)。考慮掃描線,初始每個位置 \(j\) 的值為 \(b_j\),然後掃 \(i\),每遇到一個 \(u_k = i\),把 \([0,v_k - 1]\) 加上 \(w_k\),然後求全域性 \(\min\) 即可,就處理處理 \(f\) 了。然後 \(a_x\) 的話就用個 \(set\) 維護單點改,全域性 \(\min\) 就行。複雜度 \(\Theta(n\log n)\)

P4151

題目連結

注意到隨便從 \(s\) 走到 \(t\) 搞個路徑出來,然後可以任意選環。由於異或的性質,不需要把所有環都拿出來,那可以先搞出個 dfs 樹出來,然後把每條非樹邊在上面形成的環搞出來做個線性基就行。複雜度 \(\Theta(n\log n)\)

CF938G

題目連結

用 P4151 的結論,然後套一個線段樹分治。考慮怎麼維護 dfs 樹,使用帶權並查集,但是因為每次會 findrt,所以連的邊不是真實的。那麼在連 \((u,v)\) 時,先找到 \(u\) 到根的異或和,和 \(v\) 到根的異或和,把 \(w\) 異或上它們,再連就行。複雜度 \(\Theta(n\log n(\log n + \log V))\)

P7520

題目連結

建出支配樹,發現如果一個點會改變那麼它的子樹也會被改變。那麼預處理每個點刪了它父親在原圖的反圖能走到哪些點,查詢就查除了 \(1\to u\) 的路徑的那些點就行。複雜度 \(\Theta(n(n+q))\)

CF1348F

題目連結

考慮構造一組解,貪心地,按右端點、左端點排序,每個區間取最左邊能取的值,用個 set 維護。考慮怎麼搞兩組解,感受一下就可以發現遇到一個區間,它本來還能取到更往左的值,但是已經被取了,那麼就可能與那個先取的那個區間交換。具體地,考慮設 \(L_i\) 為排列中的值 \(i\) 其被取的區間左端點,\(R_i\) 為右端點。那麼考慮從小到大列舉每個值,就是要找到一個 \(L_i \le j<i\le R_j\),那麼掃到一個值的時候往 \(R_i\) 處插入 \(i\) 以便到時候刪除,然後用個 set 維護插入刪除,每次二分找到一個 \(\ge L_i\) 的可以了。複雜度 \(\Theta(n\log n)\)

CF1419F

題目連結

先把 \(n\) 個點連邊排序,依次加邊。注意到一個點只能走到 \(4\) 個不同的位置,所以當且僅當現在只有 \(\le 4\) 個聯通塊時可能存在。所以當第一次只剩 \(4,3,2\) 個聯通塊時判斷一下,這裡最多隻有 \(3\) 種情況。每次可以考慮列舉兩個 \(x,y\) 都不同的點,算出它們所在長方形的其他兩個點,把這兩個點標記上列舉的這兩個點分別所在的聯通塊(在這些點上記錄每個聯通塊到它最短距離),然後找到一個最優的點滿足所有聯通塊到它的最遠距離最小,更新答案。注意到有 \(2\) 個聯通塊的時候不一定有上述情況,所以可以列舉兩個點算它們之間的距離即可。具體可以使用 dsu 實現,複雜度 \(\Theta(n^2 \log n)\)

CF1439B

題目連結

考慮先把所有度數大於等於 \(k\) 的點加入一個集合。然後計算出每個集合中的點鄰居有多少個,然後如果有點鄰居小於 \(k\),那就把它刪了。可以用堆維護,重複這個過程,最後如果有剩下的那就是第一合法的子集。考慮團怎麼求,相似地,我們可以考慮列舉每個度數大於等於 \(k-1\) 的點,重複上面的過程,只不過把下限調整為 \(k-1\)。考慮如果沒有 \(k-1\) 的點的話上面的點集肯定能找到,所以這個團肯定包括一個鄰居 恰好 \(k-1\) 的點,那麼我們列舉這些點,暴力 \(\Theta(k^2)\) 判斷這些點的鄰居是否組成一個團。注意到一個團有 \(\Theta(k^2)\) 條邊,而邊集是 \(\Theta(m)\) 級別的,所以合法的 \(k\) 肯定不超過 \(\Theta(\sqrt{m})\),且鄰居有 \(k-1\) 個點的點最多有 \(\Theta(\dfrac{m}{k})\) 個,所以複雜度為 \(\Theta(mk)\)\(\Theta(m\sqrt{m})\)。實現的時候會多帶個 \(\Theta(\log n)\),因為要查詢 \((u,v)\) 是否有邊。使用 unordered_map 會很慢很慢。

CF1550F

題目連結

考慮兩兩連邊,求出 mst,那麼 \(k\) 就要大於 mst 上路徑邊權最小值。考慮使用 boruvka 演算法,那麼就是每次從一個點出發,問最近能走到哪個不在同一聯通塊中的點。那麼就說要從每個 \(u\) 開始,看看 \(u-d,u+d\) 左右兩側第一個不和 \(u\) 在同一聯通塊的位置。由於 \(u-d,u+d\) 是固定的,所以可以預處理出來這兩個位置左右的第一個點。然後每次迭代之後對於每個點求出 \(L_i,R_i\) 表示左邊和右邊第一個和它不同的點。這樣就能做到 \(\Theta(n\log n)\)​ 了。

P6628

題目連結

考慮對每個 \(i\) 單獨處理就是要走一個 \(s \to i\) 的尤拉通路。那麼就說要考慮度數+連通性,因為連邊是 \(|i-j|\),所以任何 \((i,j)\) 都可以轉化為 \((i,i+1),(i+1,i+2)\cdots (j-1,j)\)。然後先把 \(m\) 條邊加進來,再加入一條 \((s,i)\) 的虛邊,對於所有奇數點排序相鄰連邊。然後連通性也是類似,把相鄰兩個不連通的點的邊加入,求 mst 就行。(加虛邊不影響連通性是因為如果 \((s,i)\) 刪了之後不在同一聯通塊,那麼就有一個聯通塊有恰好 \(1\) 個奇數點,顯然不可能)複雜度 \(\Theta(n\log^2 n)\)​。

CF1682F

題目連結

其實把所有 \(b_i < 0\) 看成 \(-b_i\) 個黑點,\(b_i > 0\) 看成 \(b_i\) 個白點,那就是兩兩匹配最短長度和。那其實就是每個點往前面第一個與它不同顏色沒匹配的匹配。直接統計是可以,但是不太方便。考慮一個 \((a_i,a_i + 1)\) 的貢獻,由於保證 \(b\) 之和是 \(0\),所以必定有 \(sum_{i-1} - sum_{l-1} = -(sum_r - sum_{i-1})\)。那麼貢獻就是 \((a_i - a_{i-1}) \cdot |sum_{i-1} - sum_{l-1}|\)。那直接離線下來,二維數點即可,可以對 \(sum\) 排序算 \([l+1,r]\) 之間的貢獻,就可以用 bit 統計了。複雜度 \(\Theta(n\log n)\)