1. 程式人生 > 實用技巧 >2020牛客多校第五場 B.Graph tire樹+最小異或生成樹+分治

2020牛客多校第五場 B.Graph tire樹+最小異或生成樹+分治

https://ac.nowcoder.com/acm/contest/5670/B

題意:

給出一個n個頂點,n-1條邊的樹,每條邊都有一個值;

現在有兩個操作,增加一條邊和刪掉一條邊,任何時候都滿足以下要求:

1.圖連通;

2.圖中的所有環滿足,每個環的邊權異或和為0; 

求圖中所有邊的邊權最小和。

思路:

(全是別人的部落格               

最大異或對:https://www.acwing.com/problem/content/description/145/

幾乎原題: cf888G:https://blog.csdn.net/zhazhaxiaosong/article/details/107682944

本題參考部落格:

https://blog.csdn.net/zhazhaxiaosong/article/details/107686336

官方題解:

總結:邊權化點權,建tire樹,求最小異或生成樹(分治實現)

程式碼:

#include <bits/stdc++.h>
using namespace std;
const long long mod =1e9+7;
typedef long long ll;
const int inf =0x3f3f3f3f;
const long long INF =0x3f3f3f3f3f3f3f3f;
const int MAXN =2e6+5;
typedef pair
<int,ll>pii; ll a[MAXN]; int son[MAXN][2],idx=0; int l[MAXN],r[MAXN]; vector<pii>g[MAXN]; void Insert(ll x,int id) { int p=0; for(int i=32;i>=0;i--) { int s=x>>i&1; if(!son[p][s])son[p][s]=++idx; p=son[p][s]; if(!l[p])l[p]=id; r[p]
=id; } } ll query(int p,int pos,ll x) { ll res=0; for(int i=pos;i>=0;i--) { int s=x>>i&1; if(son[p][s])p=son[p][s]; else { res+=(1<<i); p=son[p][!s]; } } return res; } ll solve(int p,int pos) { if(son[p][0]&&son[p][1]) { int x=son[p][0],y=son[p][1]; ll minn=1e17; for(int i=l[x];i<=r[x];i++)minn=min(minn,query(y,pos-1,a[i])+(1<<pos)); return minn+solve(son[p][0],pos-1)+solve(son[p][1],pos-1); } else if(son[p][0])return solve(son[p][0],pos-1); else if(son[p][1])return solve(son[p][1],pos-1); return 0; } void dfs(int u,int fa) { for(auto v:g[u]) { if(v.first==fa)continue; a[v.first]=a[u]^v.second; dfs(v.first,u); } } int main() { int n; scanf("%d",&n); for(int i=1;i<n;i++) { int u,v; ll w; scanf("%d%d%lld",&u,&v,&w); u++,v++; g[u].push_back({v,w}); g[v].push_back({u,w}); } dfs(1,-1); sort(a+1,a+1+n); for(int i=1;i<=n;i++)Insert(a[i],i); printf("%lld\n",solve(0,32)); return 0; }
View Code