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; }