加訓一下。
1. [ARC181E] Min and Max at the edge
場上沒人過的神題。(大概是搬運的官方題解)
先考慮如何 chk 一個圖是否存在好生成樹。觀察好生成樹的限制,發現其對於非樹邊的限制是在生成樹上連線兩點的路徑有關。而 Kruskal 的證明就是對於每條非樹邊,其邊權大於所有其路徑上的樹邊,兩者很像。
但是題目中的限制是點的限制,轉到邊上的想法是給點賦點權 \(X_i\),然後 \((u,v)\) 的邊權為 \(|X_u-X_v|\)。考慮把 \(X\) 設成一個遞增的序列,比如 \(X_i=10^i\),這樣邊權一定互不相同。
對於一棵好的生成樹,設 \(S(u,v)\) 表示 \(u,v\) 之間的樹上路徑,則對於點 \(i\) 要求 \(\forall i\in S(u,v),X_u\leq X_i\leq X_v\)。而對於邊 \((x,y)\),\(X_u\leq X_x,X_y\leq X_v\)。設其根據上述定義的邊權是 \(w(x,y)=|X_x-X_y|\),則 \(\forall (x,y)\in S(u,v),w(x,y)<w(u,v)\)。這就證明了好的生成樹一定是新圖中的最小生成樹。
因為可以構造出邊權互不相同的情況,所以這也證明了好的生成樹也是唯一的。跑出來這個圖的最小生成樹之後,檢查每條非樹邊,如果都滿足限制則該圖是好的。
但是題目有多次詢問,而且這個最小生成樹也不是那麼好求。不難發現其實圖中定義的邊權只需要滿足 \(\forall i<j<k,w(i,j)<w(i,k)\) 並且 \(\forall i<j<k,w(i,k)>w(j,k)\) ,即滿足區間包含單調性即可。
所以可以把邊 \(w(u,v)\) 賦為 \(v\times(n+1)-u\),這樣得到的生成樹一定滿足對於任意非樹邊 \((u,v)\),其路徑上的最大值就是 \(v\)。原因是非樹邊 \((u,v)\) 路徑上的邊權應當都小於 \(w(u,v)\),所以如果存在大於 \(v\) 的點則一定不合法。而且因為是 \(-u\),所以合併兩個連通塊的時候,一邊選擇的較小的點會盡可能的大,這也滿足路徑上的最小值儘量是 \(u\)。
但是這樣還是需要 chk 路徑上點的最小值是否滿足條件。可以再反著做一遍,\(w(u,v)=(n-u+1)\times(n+1)-(n-v+1)\),同理得這樣求出來的東西的最小值一定合法,最大值儘量合法。因為已經證明了好的生成樹唯一,所以判一下兩棵樹是否相同即可。
這樣就將問題轉化成了比較好的形式:刪邊求最小生成樹,可以看成是找一條非樹邊 \((x,y)\) 滿足 \(x\in \text{subtree}(i),y\notin \text{subtree(i)},w(x,y)\) 最小。轉成 dfn 序之後可以看成是兩個 3-side 矩形查最小值,可以掃描線線段樹維護,複雜度是 \(\mathcal O(n\log n)\)。
2. [ARC181F] Colorful Reversi
首先觀察一下,對於 \(a,b,c,a\) 這種情況來說,兩個 \(a\) 之間永遠不可能發生操作。而 \(a,b,c,b,a\) 這種情況,兩個 \(a\) 之間是有關聯的。有一個很天才的想法是建樹,一開始只有一個節點表示 \(a_1\),維護一個指標 \(pos\) 表示當前在樹上的哪個節點,接下來依次加入每個點 \(a_i\):
- 若 \(pos\) 所在點的顏色和 \(a_i\) 相同,則 \(pos\) 不動。
- 否則若 \(pos\) 所在點有鄰點的顏色是 \(a_i\),則 \(pos\) 走向該鄰點。
- 否則新建一個節點,顏色為 \(a_i\),\(pos\) 走向該節點。
這樣就得到了一棵操作樹,它有一些很好的性質:
- 假設生成時在上面走過的路徑是 \(B\),則操作 \(l,r\) 等價於把 \(B[l,r]=\{x,y,y\dots y,y,x\}\) 變成 \(B[l,r]=\{x,x\dots x,x\}\)。
- 對於原序列,如果能夠操作 \([l,r]\) 則 \(l,r\) 一定屬於同一個點,否則 \(l,r\) 屬於不同的點。
- 對於路徑 \(\{v_1,v_2,v_3\dots v_k\}\),透過操作將其變成 \(\{v'_1,v'_2,v'_3\dots v'_k\}\) 的最小代價是 \(\sum_{i=1}^k d(v_i,v'_i)\),其中 \(d(x,y)\) 表示兩點樹上的距離。
接下來,對於 \(pos\) 的起始節點 \(x\) 和終止節點 \(y\),最終序列的形態是若干個顏色段,而顏色恰好就是從 \(x\) 走到 \(y\) 所經過的簡單路徑上的顏色。證明很簡單,顯然路徑上兩個不同的顏色段永遠無法合併,而如果存在其他的顏色則其兩邊的顏色一定是相同的,能再操作一次。
所以拉出樹上 \(x,y\) 之間的路徑,對於此路徑外的部分一定會合併到路徑上,可以先 dfs 一遍算出貢獻,這樣可以得到從 \(B\) 得到一個新的序列 \(C\)。接下來要解決問題的就是:現在有一個序列 \(C[1,n]\),滿足 \(\forall i<n,|C_i-C_{i+1}|\leq 1\)。現在要生成一個新的序列 \(C'\),滿足:
- \(C'_1=C_1,C'_n=C_n\)。
- \(\forall i<n,C'_{i+1}-C'_i\in[0,1]\)。
- \(\forall i<n\wedge C'_{i+1}=C’_i+1,C_i=C'_i,C_{i+1}=C'_{i+1}\)。
在此基礎上滿足 \(\sum_{i=1}^n |C_i-C'_i|\) 最小。設 \(f_{i}\) 表示考慮了 \(\leq i\) 的 \(C\),\(C'_i=C_i\) 時代價的最小值,\(pre_i\) 表示 \(C_i\) 上一次出現的位置。轉移比較簡單:
因為 \(pre_i\) 是上一次出現的位置,所以對於所有的 \(j\) 要麼 \(C_j\) 全部大於 \(C_i\),要麼全部小於 \(C_i\),可以字首和處理一下 \(\mathcal O(1)\) 轉移。這樣 \(f_n\) 加上之前把樹縮成一條鏈的代價就是答案,複雜度是 \(\mathcal O(n)\) 或 \(\mathcal O(n\log n)\)。