日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【uoj#207】共价大爷游长沙 随机化+LCT维护子树信息

發布時間:2023/12/20 编程问答 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【uoj#207】共价大爷游长沙 随机化+LCT维护子树信息 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目描述

給出一棵樹和一個點對集合S,多次改變這棵樹的形態、在集合中加入或刪除點對,或詢問集合內的每組點對之間的路徑是否都經過某條給定邊。

輸入

輸入的第一行包含一個整數 id,表示測試數據編號,如第一組數據的id=1,樣例數據的 id 可以忽略。
輸入的第二行包含兩個整數 n,m,分別表示圖中的點數,以及接下來會發生的事件數,事件的定義下文中會有描述。初始時 S 為空。
接下來 n?1 行,每行兩個正整數 x,y,表示點 x 和點 y 之間有一條無向邊。
接下來 m 行,每行描述一個事件,每行的第一個數 type 表示事件的類型。
若type=1,那么接下來有四個正整數x,y,u,v,表示先刪除連接點x和點y的無向邊,保證存在這樣的無向邊,然后加入一條連接點u和點v的無向邊,保證操作后的圖仍然滿足題中所述條件。
若type=2,那么接下來有兩個正整數 x,y,表示在 S 中加入點對 (x,y)。
若type=3,那么接下來有一個正整數 x,表示刪除第 x 個加入 S 中的點對,即在第 x 個 type=2 的事件中加入 S 中的點對,保證這個點對存在且仍然在 S 中。
若 type=4,那么接下來有兩個正整數 x,y,表示小L詢問守在連接點 x 和點 y 的邊上是否一定能見到共價大爺,保證存在這樣的無向邊且此時 S 不為空。

輸出

對于每個小L的詢問,輸出“YES”或者“NO”(均不含引號)表示小L一定能或者不一定能見到共價大爺。

樣例輸入

0
5 7
1 2
1 3
2 4
1 5
2 1 5
1 1 5 2 5
4 2 5
2 1 4
4 2 5
3 1
4 2 4


題解

隨機化+LCT維護子樹信息

對與每個點對,隨機一個權值,把這個權值異或到這兩個點上。那么對于查詢,如果 x 為樹根時,y 子樹中的所有點的權值的異或和等于所有點對的異或和,則視為所有點對間的路徑都經過 x-y 。(別問我怎么想出來的。。。做過一道類似的題)

當權值范圍足夠大時可以近似視為正確。

由于樹的形態是變化的,因此需要使用LCT維護子樹信息,具體方法參見這里。

注意維護子樹信息的LCT:link時需要makeroot(x),makeroot(y);修改時需要makeroot(x)而不是簡單的splay(x);查詢時需要先makeroot(x)。

時間復雜度 $O(LCT·n\log n)$?

#include <cstdio> #include <algorithm> #define N 100010 using namespace std; int fa[N] , c[2][N] , rev[N] , w[N] , sum[N] , vx[N * 3] , vy[N * 3] , vw[N * 3] , tot; inline void pushup(int x) {sum[x] = sum[c[0][x]] ^ sum[c[1][x]] ^ w[x]; } inline void pushdown(int x) {if(rev[x]){int l = c[0][x] , r = c[1][x];swap(c[0][l] , c[1][l]) , rev[l] ^= 1;swap(c[0][r] , c[1][r]) , rev[r] ^= 1;rev[x] = 0;} } inline bool isroot(int x) {return c[0][fa[x]] != x && c[1][fa[x]] != x; } void update(int x) {if(!isroot(x)) update(fa[x]);pushdown(x); } inline void rotate(int x) {int y = fa[x] , z = fa[y] , l = (c[1][y] == x) , r = l ^ 1;if(!isroot(y)) c[c[1][z] == y][z] = x;fa[x] = z , fa[y] = x , fa[c[r][x]] = y , c[l][y] = c[r][x] , c[r][x] = y;pushup(y) , pushup(x); } inline void splay(int x) {int y , z;update(x);while(!isroot(x)){y = fa[x] , z = fa[y];if(!isroot(y)){if((c[0][y] == x) ^ (c[0][z] == y)) rotate(x);else rotate(y);}rotate(x);} } inline void access(int x) {int t = 0;while(x) splay(x) , w[x] ^= sum[c[1][x]] ^ sum[t] , c[1][x] = t , t = x , x = fa[x]; } inline void makeroot(int x) {access(x) , splay(x) , swap(c[0][x] , c[1][x]) , rev[x] ^= 1; } inline void link(int x , int y) {makeroot(x) , makeroot(y) , fa[x] = y , w[y] ^= sum[x] , pushup(y); } inline void cut(int x , int y) {makeroot(x) , access(y) , splay(y) , fa[x] = c[0][y] = 0 , pushup(y); } int main() {srand(20011011);int n , m , i , opt , x , y , u , v , now = 0;scanf("%*d%d%d" , &n , &m);for(i = 1 ; i < n ; i ++ ) scanf("%d%d" , &x , &y) , link(x , y);while(m -- ){scanf("%d%d" , &opt , &x);if(opt == 1) scanf("%d%d%d" , &y , &u , &v) , cut(x , y) , link(u , v);else if(opt == 2){scanf("%d" , &y);vx[++tot] = x , vy[tot] = y , vw[tot] = (rand() << 15) + rand() , now ^= vw[tot];makeroot(x) , w[x] ^= vw[tot] , pushup(x);makeroot(y) , w[y] ^= vw[tot] , pushup(y);}else if(opt == 3){now ^= vw[x];makeroot(vx[x]) , w[vx[x]] ^= vw[x] , pushup(vx[x]);makeroot(vy[x]) , w[vy[x]] ^= vw[x] , pushup(vy[x]);}else scanf("%d" , &y) , makeroot(x) , access(y) , splay(y) , puts(sum[x] == now ? "YES" : "NO");}return 0; }

?

轉載于:https://www.cnblogs.com/GXZlegend/p/8244009.html

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的【uoj#207】共价大爷游长沙 随机化+LCT维护子树信息的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。