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

 

posted on 2020-08-04 20:29  MZRONG  阅读(250)  评论(0编辑  收藏  举报