題目:AGC052B
題目描述:
給你一棵\(n\)個點、\(n-1\)條邊的樹,樹上每條邊的邊權\(w_{i}^{1}\)和期望邊權\(w_{i}^{2}\)均已知(\(w_{i}^{2}\)不是\(w_{i}^{1}\)平方的意思),你可以進行以下操作
- 選擇一條邊\((a,b)\),記這條邊現在的權值為\(w\),那么與這條邊相鄰的所有邊,即所有的\((a,x)\)和\((b,y)\)(邊\((a,b)\)不算)的邊權值都會異或上\(w\)
你可以進行任意次數操作,問是否存在合法的操作使得所有的邊權\(w_{i}^{1}\)都變為它對應的期望邊權\(w_{i}^{2}\)
\(n \leq 10^{5}\) 且 \(n\) 為奇數, \(0 \leq w_{i}^{1},w_{i}^{2} < 2^{30}\)
蒟蒻題解
我真的是太菜了,一場比賽就打了一個第一題,第二題就不會了
定義\(d_{u,v}\)表示\(u\)到\(v\)的簡單路徑上所有邊的權值的異或和(這個想法是我之前沒怎么接觸到的),\(f_{u,v}\)表示\(u\)到\(v\)的簡單路徑上所有邊的期望權值的異或和
當對邊\((a,b)\)進行操作時
- 若\(u \neq a\)且\(u \neq b\),則\(d_{u,a}\)的值和\(d_{u,b}\)的值會進行交換
- 若\(u = a\)或\(u = b\),假設\(u = a\),記\((u,b)\)這條邊的權值為\(w\),則對於任意點\(v\),\(d_{u,v}\)都會異或上\(w\)
假設對以點\(u\)為端點的所有邊的操作異或起來記為\(W\),那么如果答案有解,那么對於任意點\(a\),一定存在\(d_{u,a} \bigoplus W = f_{u,b}\),且\(a\)和\(b\)兩兩配對
如果存在滿足條件的\(W\),由於\(n\)是奇數,所有易得\(W = d_{u,1} \bigoplus d_{u,2} \bigoplus ··· \bigoplus d_{u,n} \bigoplus f_{u,1} \bigoplus f_{u,2} \bigoplus ··· \bigoplus f_{u,n}\)
那么題目可以轉換為:是否存在合法操作,使得對於任意點\(u\),以\(u\)為端點的邊的操作異或能構成\(W\),且\(d_{u,a} \bigoplus W\)和\(f_{u,b}\)兩兩對應相等
假設對於一個點\(u\),想要判斷是否存在操作能來構成\(W\)不太好做,我們可以先看看后面的要求:要滿足\(d_{u,a} \bigoplus W\)和\(f_{u,b}\)兩兩對應相等
由於我們已知\(W = d_{u,1} \bigoplus d_{u,2} \bigoplus ··· \bigoplus d_{u,n} \bigoplus f_{u,1} \bigoplus f_{u,2} \bigoplus ··· \bigoplus f_{u,n}\),那么\(d_{u,a} \bigoplus W = f_{u,b}\)就相當於\(d_{u,a} \bigoplus W \bigoplus f_{u,b} = 0\),即將構成\(W\)的一系列異或值去掉\(d_{u,a}\)和\(f_{u,b}\),其他值異或起來為\(0\),也就是說\(d_{u,1} \bigoplus d_{u,2} \bigoplus ··· \bigoplus d_{u,a-1} \bigoplus d_{u,a+1} \bigoplus ··· \bigoplus d_{u,n} = f_{u,1} \bigoplus f_{u,2} \bigoplus ··· \bigoplus f_{u,b-1} \bigoplus f_{u,b+1} \bigoplus ··· \bigoplus f_{u,n}\),也就是說,我們能用若干\(d_{u,x}\)去表示\(f_{u,y}\),原本構成\(W\)需要\(d\)和\(f\),可以全部轉換成\(d\)的形式,所以如果滿足\(d_{u,a} \bigoplus W\)和\(f_{u,b}\)兩兩對應相等,那么\(W\)也能被構建出來
但是一共有\(n\)個點,每個點都去判斷一次,單次判斷復雜度是\(\Theta(nlog\ n)\),總的復雜度是\(\Theta(n^{2}log\ n)\)的
不妨去試一下,一個點成立,能否推廣到其他點也成立
若\(u\)滿足條件,那么假設\(v\)與\(u\)有連邊,這條邊的初始權值為\(w ^ {1}\),期望權值為\(w ^{2}\),那么\(d_{v,a} = d_{u,a} \bigoplus w ^ {1}\),\(f_{v,a} = f_{u,a} \bigoplus w ^ {2}\),\(W_{v} = W_{u} \bigoplus w ^ {1} \bigoplus w ^ {2}\),假設原本存在\(d_{u,a} \bigoplus W_{u} = f_{u,b}\),那么現在\(d_{v,a} \bigoplus W_{v} = f_{v,b}\)也同樣成立
總結:對於節點\(u\),判斷是否存在\(d_{u,a} \bigoplus W\)和\(f_{u,b}\)兩兩對應相等,時間復雜度是\(\Theta(nlog\ n)\)
參考程序:
#include<bits/stdc++.h>
using namespace std;
#define Re register int
const int N = 100005;
int n, cnt, s, val1[N], val2[N], hea[N], nxt[N << 1], to[N << 1], wi1[N << 1], wi2[N << 1];
inline int read()
{
char c = getchar();
int ans = 0;
while (c < 48 || c > 57) c = getchar();
while (c >= 48 && c <= 57) ans = (ans << 3) + (ans << 1) + (c ^ 48), c = getchar();
return ans;
}
inline void add(int x, int y, int z1, int z2)
{
nxt[++cnt] = hea[x], to[cnt] = y, wi1[cnt] = z1, wi2[cnt] = z2, hea[x] = cnt;
}
inline void dfs(int x, int y)
{
for (Re i = hea[x]; i; i = nxt[i])
{
int u = to[i];
if (u == y) continue;
val1[u] = val1[x] ^ wi1[i], val2[u] = val2[x] ^ wi2[i];
dfs(u, x);
}
}
int main()
{
n = read();
for (Re i = 1; i < n; ++i)
{
int u = read(), v = read(), w1 = read(), w2 = read();
add(u, v, w1, w2), add(v, u, w1, w2);
}
dfs(1, 0);
for (Re i = 1; i <= n; ++i) s ^= val1[i] ^ val2[i];
for (Re i = 1; i <= n; ++i) val1[i] ^= s;
sort(val1 + 1, val1 + n + 1), sort(val2 + 1, val2 + n + 1);
for (Re i = 1; i <= n; ++i)
if (val1[i] ^ val2[i])
{
puts("NO");
return 0;
}
puts("YES");
return 0;
}