ds 合集的 Part 2,此合集包含分治問題和位問題。
分治問題
CF452F
題目連結
列舉 \(i\),考慮差為 \(k\),即 \(a_i - k,a+k\) 是否在不同的兩側。把在 \(i\) 前面的 \(a_j\) 設為 \(1\),就是要找以 \(i\) 為中心半徑在 \(\min(a_i,n-a_i + 1)\) 的串是否是迴文串。線段樹維護即可。複雜度 \(\Theta(n\log n)\)。
CF480E
題目連結
倒序加點處理,設 \(f_{i,j}\) 為 \((i,j)\) 能往上走幾步,\(g_{i,j}\) 往下。每次加點 \((x,y)\) 只會影響 \(f_{i,y},g_{i,y}\),可以 \(\Theta(nk)\) 修改。考慮每次對答案的增加,顯然是列舉 \(x\) 這一行,然後 \([l,r]\) 合法當且僅當 \(\min\limits_{k\in [l,r]} f_{x,k} + \min\limits_{k\in[l,r]} g_{x,k} - 1 \ge r - l + 1\)。由於答案是單調的,所以直接列舉上次答案 \(ans+1\),作為 \(r-l+1\),做一個滑動視窗就行。複雜度 \(\Theta(nk)\)。
CF549F
題目連結
考慮分治,列舉最大值的一邊,設最大值在左邊,那麼列舉 \(i\),也就是問有多少個 \(j\) 滿足 \(j\in [mid+1,r],sum_{mid} - sum_{j} \equiv sum_{mid} -sum_{i-1}-\max\limits_{p\in[i,mid]} a_p \pmod{k}\),可以考慮雙指標實現。複雜度 \(\Theta(n\log n)\)。
CF750E
題目連結
考慮 \([1,n]\) 怎麼做,設 \(f_{i,0/1/2/3/4}\) 為前 \(i\) 個匹配到 \(\empty,2,0,1,7\) 的最小代價。轉移為設當前字元是 \(x\)(第 \(x\) 個),那麼有 \(f_{i,x-1} = f_{i-1,x-1}+1,f_{i,x}=\min{f_{i-1,x},f_{i-1,x-1}},f_{i,j}=f_{i-1,j}(j\neq x \and j\neq x-1)\)。特別地,如果這一位是 \(6\),那麼有 \(f_{i,3}=f_{i-1,3}+1,f_{i,4}=f_{i-1,4}+1\)。區間詢問使用廣義矩乘做就行,可以倍增做。複雜度 \(\Theta(nk^3 \log n)\),其中 \(k=5\)。
CF763E
題目連結
跟 CF811E 類似,由於一個點只會連與它距離不超過 \(k\) 的點,所以如果一個聯通塊最左、最右是 \(l,r\),並且 \([l-k,l-1],[r+1,r+k]\) 都沒有跟這個聯通塊相連的,那麼再往外就不可能有與它相連的了。所以也考慮線段樹維護 \([l,r]\),記錄 \([l,r]\) 的聯通塊個數,並且維護 \([l,l+k-1],[r-k+1,r]\) 每個點所在的聯通塊。合併直接開個 \(4k\) 大小空間的並查集合並這些點就好了,注意區間小的時候還要更新左邊和右邊的 \(k\) 個點。複雜度 \(\Theta(nk^2 \log n)\)。
CF848C
題目連結
套路地將最後一次出現的下標描述成 \(nxt_i >r\) 的 \(i\)。那麼答案就是 \(\sum\limits_{i=l}^r i[nxt_i > r]-\sum\limits_{i=l}^r i[pre_i < l]\)。那麼考慮一個 \((i,nxt_i)\),將 \([1,i][i,nxt_i - 1]\) 區間加上 \(i\),把 \((i,pre_i)\) 的 \([pre_i + 1,i][i,n]\) 矩陣減去 \(i\)。再開 \(\Theta(V)\) 個 set 維護每個值出現位置,每次單點修改只用更新 \(\Theta(1)\) 個值。所以就要支援矩陣加,單點求值。線上就可以樹套樹,離線可以 cdq 三維數點。複雜度 \(\Theta(n\log^2 n)\)。
CF1004F
題目連結
經典 trick 是字首或和不超過 \(\log V\) 段。所以線段樹上直接維護被完全包含在當前區間的答案和字首、字尾的或和 段。合併的時候,字尾從右邊繼承,再接上左邊,字首同理。答案是左邊加上右邊,然後再做個雙指標,左邊從 \(mid\) 往左掃,右邊從 \(mid+1\) 往右掃即可,合併複雜度 \(\Theta(\log V)\)。單點改就直接改。所以總複雜度就說 \(\Theta(n\log n \log V)\)。
CF1140F
題目連結
注意到滿足要求的肯定是一個缺一個角的矩形,補上去會形成一個完整的矩形。然後再考慮一直這樣做最後會形成什麼,就是會形成一堆矩形,且它們的行列都是不同的。這啟發我們找一個聯通塊,然後就會注意到如果對於每個點,把它的行列連邊,最後得出來的每個聯通塊就會形成一堆矩形。考慮線段樹分治,並查集維護連通性和行列數量即可。複雜度 \(\Theta(n\log^2 n)\)。
CF1316F
題目連結
即求每個子序列的代價和,考慮對每個相鄰點對 \((a_i, a_{i+1})\) 求貢獻。考慮線段樹維護值域,對每個區間 \([l,r]\) 記錄只保留值在 \([l,r]\) 的點的所有點對值乘方案的和,每個點的 \(p_i \times 2^{L_i}\) ,\(L_i\) 為 \(i\) 左邊的點數,和 \(p_i \times 2^{R_i}\),記作 \(suml,sumr\),還有區間中的點數 \(cnt\) 。合併時,\(ans=ans_{ls} \times 2^{cnt_{rs}} + ans_{rs} \times 2^{cnt_{ls}}+suml_{ls} \times sumr_{rs}\),\(suml = suml_{ls} +suml_{rs}\times 2^{cnt_{ls}},sumr=sumr_{ls} \times 2^{cnt_{rs}} + sumr_{rs},cnt=cnt_{ls}+cnt_{rs}\)。 因為有重複的值,所以對所有可能出現的數排序放到下標就行。複雜度 \(\Theta(n\log n)\)。
CF1371F
題目連結
考慮線段樹維護每個區間正著和反著的資訊。考慮答案需要記錄什麼,要知道從一端走能到達哪裡,要知道兩端溢位了多少球。於是線段樹記錄 \(ans,tL,tR,L,R\) 分別表示此區間的答案,左邊溢位的球,右邊溢位的球,(從左邊加球能到達的位置,那個位置的球數量),右邊同理。轉移是簡單的。
c.tL = (R.se == l ? tL + b.tL : tL), c.tR = (b.L.se == b.r + 1 ? b.tR + tR : b.tR);
c.L = (L.se == b.l ? make_pair(tR + b.L.fi, b.L.se) : make_pair(L.fi + (R.se == L.se ? b.tL : 0), L.se));
c.R = (b.R.se == b.l ? make_pair(b.tL + R.fi, R.se) : make_pair(b.R.fi + (b.R.se == b.L.se ? tR : 0), b.R.se));
c.l = l, c.r = b.r;
區間取反直接打標記,交換正反資訊即可。複雜度 \(\Theta(n\log n)\)。
CF1373G
題目連結
一個點如果一直往第 \(k\) 行走,設它最前能到達的格子為 \(x\),那麼它可以被放到 \([x,n]\) 這些格子裡。那麼要把一堆點都能放完的話,設 \(suf_i\) 為 \([i,n]\) 有多少個 \(x\),條件就是 \(\forall i,suf_i \le m-i+1\) 即 \(suf_i + i - 1\le m\),最小的 \(m\) 即 \(suf_i + i - 1\) 的最大值。
考慮動態修改,使用線段樹維護,每次插入一個 \(x\) 把 \([1,x]\) 加 \(1\),刪除減 \(1\),查全域性最大即可。複雜度 \(\Theta(n\log n)\)。
CF1379F2
題目連結
考慮相鄰兩行,注意到每相鄰兩行 \((2x+1,2x+2)\) 直接最多隻能放 \(m\) 個,又因為只有 \(2n\) 行,所以每相鄰兩行必須放 \(m\) 個。顯然,這 \(m\) 個如果能放到 \(2x+1\) 這行肯定最優,否則就是 \(2x+1\) 這行有個地方擋住了,只能放到 \(2x+2\) 行,那麼上面就是一個字首,下面就是一個字尾,分別對應 \(1\) 到 \(2x+1\) 這行第一個空缺的位置 \(x\),\(2x+2\) 行最後一個空缺的位置 \(y\) 到 \(2m\),所以這裡要求 \(x> y\),設上面那行是在第 \(t\) 個放完後終止的,那麼 \(t\in [\dfrac{y}{2},\dfrac{x-1}{2}]\)。並且要求 \(\forall i,t_i \ge t_{i+1}\)。
問題轉化為,給定 \(n\) 個區間,動態修改區間,要求在每個區間中取一個數,且這個數不能大於上次取的。由於擴充區間不好做,不妨使用線段樹分治把動態修改區間改為動態縮減區間。貪心的想法是每個區間儘量往右取,那麼每取完一個 \(x\) 就直接對後面所有區間的 \(r\) 對 \(x\) 取 \(\min\) 即可,如果碰到一個 \(l>r\) 就是不合法的了。
複雜度 \(\Theta(n\log^2 n)\)。
CF1439C
題目連結
看到形如 \(y \ge a_i,y\to y-a_i\) 的形態,第一時間想倍增分塊。注意到這個 \(a\) 無論何時都是不增的,這也就避免了倍增分塊中要考慮 \(<2^k\) 的和的情況。
那麼現在思路就明確了,若現在在 \(x\),設能連續取的極長長度為 \(len\),也就是能連續取完 \([x,x+len-1]\)。若 \(len < n-x+1\),那麼 \(y\) 必定會減半,因為若不減半,最後一個取的一定小於 \(\dfrac{y}{2}\),後一個依然小於 \(\dfrac{y}{2}\),那麼顯然可以再取一個。
考慮怎麼跳,顯然直接線上段樹上二分找到下一個位置即可。考慮修改,如果直接吉司機當然可以,但是每必要,也是直接二分找到第一個 \(<y\) 的位置即可。
複雜度 \(\Theta(n\log n \log V)\)。
CF1386C
題目連結
首先觀察奇環怎麼處理,只需要找到一棵生成樹然後對於每個非樹邊看看和樹邊形成的環是否為奇環即可,可以使用帶權並查集維護。具體地,當連線一條邊時,由於並查集上的邊不是真實的邊,所以找到 \((x,y)\) 到 \((rt_x,rt_y)\) 的邊權異或和,將其異或 \(1\) 然後作為 \((rt_x,rt_y)\) 的邊權。每次查詢 \((x,y)\) 直接找到 \((x,y)\) 到根的邊權異或和異或起來是 \(0\) 即可。
- 解法一 \(\Theta(n\sqrt{n})/\Theta(n\sqrt{n}\log n)\)
考慮把邊的序列複雜一邊接到後面,然後每次詢問就是用一個區間的邊。使用不刪除莫隊,直接維護即可。複雜度可能帶個 \(\log\),由於要撤銷並查集,不能使用路徑壓縮。
- 解法二 \(\Theta(n\log n)/\Theta(n\log^2 n)\)
考慮令 \(nxt_i\) 為以 \(i\) 作為左端點,最遠的 \(r\) 使得刪掉 \([i,r]\) 這段區間還有奇環。顯然 \(nxt_i\) 是隨 \(i\) 單調不降的。考慮使用分治最佳化決策單調性,設 \(f(l,r,L,R)\) 為處理 \([l,r]\) 的 \(nxt\),並且值域(即決策點)在 \([L,R]\) 範圍內。遞迴到 \(f(l,r,L,R)\) 時,應先加入所有除了 \([l,R]\) 的邊,然後令 \(mid = \lfloor\dfrac{l+r}{2}\rfloor\),考慮從 \(R\) 往 \(L\) 依次加入每條邊,一旦有奇環那麼 \(nxt_{mid}\) 就設為當前列舉的邊。然後就遞迴地呼叫 \(f(l,mid-1,L,nxt_{mid})\),注意此時不需要撤銷 \([nxt_{mid}+1,R]\) 的邊。然後處理完左邊後撤銷掉 \([nxt_{mid} + 1,R]\) 的邊,加入 \([l,mid]\) 的邊,再做 \(f(mid+1,r,nxt_{mid},R)\)。返回的時候再撤銷掉即可。複雜度也會多個 \(\log n\),因為並查集。
CF1442D
題目連結
先觀察一下最後答案長什麼樣,發現一定是一堆整串再加上至多一個字首。因為若有兩個字首,可以考慮把下一個數較大的字首往後取一位,另一個最後刪一位,一定是更優的。所以問題轉化為有 \(n\) 個物品,每個重量 \(len_i\),價值 \(sum_i\),且能額外取一個字首,要求取的重量不超過 \(n\)。
樸素的想法是列舉那個字首在的串,然後其他的用個揹包,但因為是最最佳化,所以不能可撤銷揹包來搞。既然不能直接刪除一個物品,那麼考慮不用刪除物品的分治。當在做 \(f(l,r)\) 的時候,若下一步做 \(f(l,mid)\),那麼先把當前的揹包值記錄下來,然後加入 \([mid+1,r]\) 這些物品,再遞迴下去。返回的時候還原之前記錄的揹包陣列,然後加入 \([l,mid]\),再做右邊 \(f(mid+1,r)\)。這樣的話一個節點的複雜度是 \(\Theta(len\cdot k)\)。
總複雜度為 \(\Theta(nk\log n)\)。
CF1648D
考慮一個樸素 dp,設 \(f_i\) 為走到 \((2,i)\) 的最大價值,\(sum_i\) 為第二行的字首和,\(a_i\) 為第一行的字首和,\(b_i\) 為第三行的字尾和。轉移有 \(f_i = sum_i + \max\limits_{j<i}(\max(f_j-sum_{j},a_j-sum_{j-1}) -\min\limits_{l_x \le j \le r_x} k_x)\) 。重點在於 \(-\min\limits_{l_x \le j \le r_x} k_x\)。
考慮分治,用 cdq 的思想,先把左邊的 \(f\) 處理出來,然後透過 \(j\in [l,mid]\) 去更新 \(i\in [mid+1,r]\),先對左邊 \([l,mid]\) 記錄字尾最大 \(suf_i = \max\limits_{j=i}^{mid} \max(f_j-sum_{j},a_j-sum_{j-1})\)。考慮把 \((l,r,k)\) 分為兩種。
- \(r_x \in [mid+1,r]\) 那麼可以對 \(i\in [mid+1,r_x]\) 的 \(f_i\) 對 \(suf_{\max(l_x,l)} - k_x\) 取最大。由於每個這樣的 \((l,r,k)\) 只會出現 \(\Theta(\log n)\) 次,複雜度 \(\Theta((n+q)\log n)\)。
- \(r_x>r\) 那麼這樣的 \((l,r,k)\) 一定是在當前節點的祖先是出現在第一種的,並且是遞迴到了左邊。那麼考慮在那個祖先的地方遞迴到左邊的時候在 \(l_x\) 處插入一個 \(k\)。
- 若 \(l_x \ge l\) 在做 \(suf_i\) 的是時候直接找到 \([l,i]\) 中最小的 \(k_x\) 即可,用它更新所有 \([mid+1,r]\)。
- 否則的話一定是上面那種遞迴到右端點的,這時候的分治區間被 \([l_x,r_x]\) 完全包含,所以記錄最小那個即可。
總複雜度為 \(\Theta((n+q)\log n)\)。
CF1654F
題目連結
考慮異或的性質,若第 \(i\) 位為 \(1\),那麼就是將原序列以 \(2^{i-1}\) 為一塊分成若干塊,奇數塊和偶數塊交換。設 \(f(x,i)\) 為異或 \(x\) 形成的新序列的前 \(2^i\) 個形成的序列,那麼顯然 \(f(x,i)=f(x,i-1)+f(x\oplus 2^{i-1},i-1)\)。設 \(g(x,i)\) 為異或 \(x\) 形成的新序列的前 \(2^i\) 個數在異或 \([0,2^n -1]\) 形成的所有新序列中的排名,那麼直接以 \((g(x,i-1),g(x\oplus 2^{i-1},i-1))\) 為關鍵字排序即可得到 \(g(x,i)\)。複雜度 \(\Theta(n\log^2 n)\)。
CF1693D
題目連結
首先觀察一下,發現無解的充要條件是存在一個四元組 \((a,b,c,d)\) 滿足 \(a<b<c<d\) 使得 \(p_b > p_a > p_d > p_c\) 或 \(p_c > p_d > p_a > p_b\)。因為這兩種形態滿足它們都是兩個上升或下降子序列組成的且都不相交。然後考慮統計,設 \(pre_i\) 為 \(i\) 之前最大的 \(j\) 滿足區間 \([j,i]\) 無解,考慮第二種形態,設 \(L_i\) 為 \(i\) 前面第一個大於 \(p_i\) 的點,\(R_i\) 為 \(i\) 後面第一個小於 \(p_i\) 的點。所以 \(pre_i\) 就是最大的 \(j\) 滿足 \(R_j < L_i,p_j<p_i\),直接二維偏序,bit 維護即可。第一種形態可以直接把序列變成 \(n-p_i + 1\) 再做一遍就行。複雜度 \(\Theta(n\log n)\)。
CF1730E
題目連結
先預處理每個位置是最大值的區間 \([L_i,R_i]\) 滿足 \(\forall j \in [L_i,i-1],a_j < a_i \land \forall j\in [i+1,R_i],a_j \le a_i\),再預處理每個數前面第一個比它小的和後面第一個比它小的位置 \(pre_i,suf_i\),可以單調棧 \(\Theta(n)\) 預處理。
考慮列舉最大值的位置 \(i\),列舉 \(a_i\) 的因數 \(x\)。找到 \(i\) 前面 \(x\) 第一個出現的位置 \(lst\) 和 \(i\) 後面第一次出現的位置 \(nxt\)。討論 \([lst,i]\) 和 \([i,nxt]\) 是否最小值是 \(x\)。若 \([lst,i]\) 最小值為 \(x\),那左端點可以取到 \([\max(L_i,pre_{lst}),lst]\),否則若 \([i,nxt]\) 最小值是 \(x\),那麼左端點可以取到 \((suf_{lst},i]\),右端點可以取到 \([nxt,\min(R_i,suf_{nxt})]\)。右邊同理。若 \(lst\) 不存在,左端點可以取到 \([pre_{nxt},i]\),右端點同上。\(nxt\) 不存在同理。
設值域為 \(m\),複雜度 \(\Theta(m\log m + nd(m))\)。
位問題
CF241B
題目連結
考慮先找到第 \(m\) 大的兩兩異或值。二分答案 \(x\),然後對每個數 \(a_i\) 找到所有 \(j<i,a_i\oplus a_j \le x\) 的 \((i,j)\) 對數,可以用 trie 實現,這部分複雜度 \(\Theta(n\log^2 a)\)。
然後可以先找到前 \(m\) 大有多少個 \(x\),可以用 \(m\) 減去異或和 \(\le x-1\) 的對數得到。那麼就是求 \(\sum\limits_{i=1}^n \sum\limits_{j=1}^{i-1} [a_i \oplus a_j < x] (a_i \oplus a_j)\)。也可以用 trie 實現,查詢 \(i\) 時,可以先找到 trie 上哪些子樹裡的數是合法的,然後拆位算貢獻,對於 trie 上每個節點記錄它子樹中第 \(j\) 位是 \(0/1\) 的數的個數,異或上 \(x\) 對應位即可。複雜度也是 \(\Theta(n\log^2 a)\)。
總複雜度 \(\Theta(n\log^2 a)\)。
CF633G
題目連結
注意到 \(m\) 很小,可以對每個點記錄子樹中每個值的出現情況。設 \(f_{i,j}\) 表示值 \(j\) 是否在 \(i\) 子樹中出現,對 \(i\) 子樹加 \(v\) 相當於將其向右迴圈移位 \(v\) 次。但是由於子樹加 \(v\) 還會影響祖先的 \(f\) 值,所以不能這樣維護。
考慮換種方式,查的時候直接將子樹裡的值或起來就行。使用線段樹 + dfn 序列維護,每次相當於區間迴圈移位,區間求或,可以套個 bitset,複雜度 \(\Theta(\dfrac{m(n+q\log n)}{w})\)。
CF796F
題目連結
考慮操作 \(1\)。
- 若 \([l,r]\) 中已確定的最大值為 \(x\),則表示剩下的區間中的每個數都小於等於 \(x\)。
- 若 \([l,r]\) 中已確定的都小於 \(x\),那麼剩下的區間中每個數都小於等於 \(x\),且存在一個數為 \(x\)。
現在問題轉化為,給定若干個限制(可能達到 \(\Theta(n^2)\) 級別)表示一個區間的數小於等於一個數,或者一個區間的數小於等於一個數且存在一個數等於。那麼按照 \(x\) 從小到大排序,顯然只用考慮所有之前沒覆蓋的位置,如果是第二種限制,那就先隨便欽定一個位置為 \(x\),若還有剩下位置沒欽定,那麼設之前自己確定的所有位置或和為 \(sum\),從高到低列舉每個位置,若 \(sum\) 這個位置為 \(0\) 且加上後不超過 \(x\) 就加上,顯然最多確定兩個數就能到達目前的最優了。
那麼還有一個問題,就是限制是 \(\Theta(n^2)\) 級別的,該如何最佳化?注意到每次操作只會改一個點,那麼處理出來每個點什麼時候第一次被改即可,套上個線段樹分治,每次直接找每個包含 \(t\) 的在 \([l,r]\) 中的點刪掉即可。
複雜度 \(\Theta(n\log^2 n)\)。
CF1511G
題目連結
題目就是要求 \(\oplus_{i=l}^r (a_i - l)\),\(a_i\) 是值是 \(i\) 的所有數異或和。考慮倍增,設 \(f_{i,j}\) 為 \(l=i\) 時 \([i,i+2^{j} -1]\) 區間的異或和,此時這個區間裡所有數減 \(i\) 的第 \(j\) 位都必定是 \(0\)。那麼轉移的時候,由於 \([i+2^{j-1},i+2^j - 1]\) 這段區間減 \(i+2^{j-1}\) 的第 \(j-1\) 位也是,所以可以直接異或上 \(2^{j-1}cnt_{i+2^{j-1},i+2^j-1}\),即 \(f_{i,j}=f_{i,j-1}\oplus f_{i+2^{j-1},j-1}\oplus (2^{j-1}\times (cnt_{i+2^{j-1},i+2^j - 1} \operatorname{mod} 2))\)。
回答詢問也是類似搞即可。複雜度 \(\Theta((m+q)\log m)\)。
CF1730F
題目連結
先求出 \(p\) 的逆排列 \(pos\),然後就是把每個數 \(i\) 填到 \(p\) 裡面,滿足 \(i\) 出現在 \(j\) 前面時 \(i \le j+k\),求 \(pos_i\) 的逆序對最大。
對於任意的 \(i\),\(q\) 前 \(i\) 個數中所有 \(\le i-k\) 的數都必須存在。
證明:若存在 \(x\le i-k\) 且 \(x\) 不在 \(q\) 中前 \(i\) 個數,則 \(q\) 中前 \(i\) 個數的最大值 \(t \ge i+1\),由於 \(x\) 不在前 \(i\) 箇中,所以 \(t\le x + k \le i\),又因為 \(t\ge i+1\),故矛盾。
對於任意的 \(i\),\(q\) 前 \(i\) 個數中所有 \(>i+k\) 的數都不能存在。
證明:若存在 \(x>i+k\) 在 \(q\) 前 \(i\) 個數中,則 \(q\) 中前 \(i\) 個數中第一個沒出現的數 \(t \le i\),由於 \(x\) 在 \(t\) 前面,所以 \(x\le t+k\),即 \(t>i\),矛盾。
那麼可以得出前 \(i\) 個數中不確定是否存在的數只有 \([i-k+1,i+k]\) 這 \(2k\) 個。
對於任意的 \(i\),\(q\) 前 \(i\) 個數肯定是一段連續的值域再加上 \([i+1,i+k+1]\) 的某些數
這是顯然的。
設 \(f_{i,j}\) 為加入了前 \([1,i]\) 這些數,\([i+1,i+k+1]\) 的出現情況是 \(j\) 的最小逆序對個數,列舉轉移即可。複雜度 \(\Theta(n^2 + nk2^k)\)。