考慮乙個簡單的思路,每當新增一條路徑,我們就把在這條路徑上的所有邊的邊權都異或上乙個隨機值,然後對於任意一條需要詢問的邊,我們只需要判斷它的權值是否等於目前所有的路徑的權值的異或和即可。
當我們的權值很大的時候,出錯的概率很低,所以可以近似為正確的。
但是樹的形態也需要動態修改,這就說明一條路徑在不同的版本中,它所代表的邊是不一樣的,這就很麻煩。
但是仔細觀察一下就可以發現,新加的邊一定會在樹上形成乙個環,然後所有在環中經過那條需要刪除的邊的路徑都會繞道,也就是在環上走原來的路徑的補集,這樣的話,我們只要將整個環異或上這個刪除的邊的邊權,這樣便正好達到了取補集的效果。
於是只需要用lct維護一下邊權和即可。
/************************************====
* author : ylsoi
* time : 2019.1.28
* problem : uoj207
* e-mail : [email protected]
* ***********************************=*/
#include
#define rep(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define drep(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
#define debug(x) cout<<#x<<"="<#define pii pair
#define fi first
#define se second
#define mk make_pair
#define pb push_back
typedef
long
long ll;
using
namespace std;
void
file()
template
<
typename t>
void
read
(t &_)
const
int maxn=
3e5+10;
const
int mod=
2e9;
int task_id,n,m;
struct link_cut_tree
if(laz[o])}
void
rotate
(int o)
void
splay
(int o)
drep
(i,cnt,1)
pushdown
(st[i]);
for(
int f;
!isrt
(o);
rotate
(o))
}void
access
(int o)
}void
mkrt
(int o)
void
split
(int x,
int y)
void
link
(int x,
int y)
void
cut(
int x,
int y)
void
update
(int x,
int y,
int z)
}t;int cnte,sum,w[maxn]
,tot;
pii node[maxn]
;setg[maxn]
;set
::iterator it;
inte
(int x,
int y)
intmain()
int ty,x,y;
rep(i,
1,m)
else
if(ty==2)
else
if(ty==3)
else
if(ty==4)
}return0;
}
uoj 207 共價大爺遊長沙
miaom又來做lct了!lych 無敵 由於不是很懂lct子樹資訊維護的那套理論,想了好久 搞得樹剖的子樹維護就會了一樣!首先是乙個很巧妙的轉化 將邊在鏈上轉化為這條邊能將鏈的頂點分開。給每組頂賦乙個隨機權,每次可以把邊斷掉,查詢每個聯通塊內權值異或和是否等於所有頂點權值異或和,就是子樹異或和。然...
UOJ207 共價大爺遊長沙
uoj 神題 給每個點對隨機乙個權值,把這兩個點的權值異或上這個隨機的值 用l ctl ct 維護子樹資訊,若子樹異或和為所有點對的異或和那麼就是答案 大常數 include define rg register define il inline define fill a,b memset a,b...
UOJ207 共價大爺遊長沙
link 我們知道一條邊被所有路徑經過就是其乙個端點的子樹中包含了所有路徑的一端。那麼我們可以給每條路徑的端點rand乙個隨機權值,然後用lct維護子樹異或和,查詢就是看子樹異或和是否等於所有隨機權值的異或和。lct維護子樹資訊 單點修改就是多維護乙個虛子樹資訊,改變虛邊的時候修改一下就好了。這個方...