原題鏈接
這是一道有(du)趣(liu)的數據結構題
首先發現無修改詢問,所以珂以莫隊。然后發現你要維護當前的圖是否為二分圖,這顯然珂以大力LCT維護最大生成樹。然后復雜度就變成了驚人的\(O(N\sqrt N\log N)\),附加大常數驚喜。顯然,不加任何卡常技巧,這是過不去的;用了許多卡常技巧,這也是過不去的。
我們必須考慮換個路子。觀察一下Subtask\(3\),珂以發現當詢問中的\(l\)為常數時,有一個臨界值\(r\),使得:\(\forall k\in [l,r)\),詢問\((l,k)\)對應的圖不是二分圖;\(\forall k\in [r,m]\),詢問\((l,k)\)對應的圖是二分圖。所以這個Subtask便珂以預處理出這個臨界值,這顯然珂以用LCT在\(O(N\log N)\)內實現。
我們把上述對於\(l\)的臨界值定義為\(A_l\)。進一步思考,我們會發現:\(\forall l_1\le l_2\),不等式\(A_{l_1}\le A_{l_2}\)恆成立,即數組\(A\)是單調不減的。又由於LCT支持加邊和刪邊,於是,我們珂以雙指針來預處理出數組\(A\)。這樣復雜度依舊是優秀的\(O(N\log N)\),珂以通過所有Subtask。
Q: 窩不會LCT腫么辦?
A: 那就用那個不用LCT的做法唄。
不用LCT是什么做法?我們珂以發現,LCT在上述算法中,只是來維護最大生成樹,判斷二分圖的。那為什么上述算法中LCT是必要的呢?因為在雙指針的過程中,我們要在加邊和刪邊的操作之余判斷二分圖,當加邊和刪邊無任何順序時,LCT是必要的。
那么不用LCT的做法,就是要讓加邊和刪邊的操作有順序,即每一次加邊時把這個邊放入一個棧里,刪邊時就彈棧。這時刪邊操作就變成了回滾操作。於是我們珂以用常數較小的可撤銷並查集來代替常數巨大的LCT。
然而,雙指針並不能用一個棧來維護。於是我們珂以考慮分治:定義分治函數\(S\)維護四個值\(l,r,L,R\),其中前提條件滿足\(\forall i\in[l,r],A_i\in[L,R]\),且在調用\(S(l,r,L,R)\)時,可撤銷並查集內已有\([1,l-1]\cup [r+1,m]\)內的所有邊。設\(M=(l+r)/2\),則珂以先在\(O(n)\)內算出\(A_M\)。這時\(\forall i\in[l,M-1],A_i\le A_M\),且\(\forall i\in [M+1,r],A_i\ge A_M\)。所以珂以在\(S(l,r,L,R)\)中調用\(S(l,M-1,L,A_M)\)和\(S(M+1,r,A_M,R)\)。注意要在調用之前往可撤銷並查集內插入相應的邊,然后在調用結束后回滾掉。又因為\(S\)調用中區間的總長度為\(O(N)\)級別,再加上可撤銷並查集的\(O(\log N)\),所以時間復雜度為\(O(N\log^2 N)\)。因為常數較小,所以跑得和LCT的\(O(N\log N)\)差不多快。
代碼?不存在的。