B Graph(异或MST)

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

题意:给定初始树[u,v,w],可以对树进行增加任意权重边,和删除任意边,前提是这个过程中图要保证连通且若有环则要保证环异或和为0

分析:可以发现任意两个点之间连边的权值都是固定的。由于图始终联通,所以两点间始终存在至少一条 路径,如果存在多条,根据环的异或和为0,两点间的路径的异或和应该相等,且始终是固定的。 

   将点权转化为边权,具体就是dfs从根到节点i的路径异或和。因为这样在套入trie树时,若选择连接节点u,v,那么权重就是根节点到u的异或和 异或上 根节点到v的异或和,这样就可表示要连接u,v的权重要是u到v的路径异或和(为了达到”保证环异或和为0“这个条件)

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define MP make_pair
typedef long long ll;
const int mod=1e9+7;
const int M=1e5+5;
const int inf=0x3f3f3f3f;
const ll INF=1e18;
int a[M],trie[M*32][2];
int pos[M*32];
vector<int>v[M];
int tot=1;
ll ans=0;
struct node{
    int v,w;
};
vector<node>g[M];
void pn(){
    cout<<"NO"<<'
';
}
void py(){
    cout<<"YES"<<'
';
}
void dfs1(int u,int fa){
    for(auto it:g[u]){
        if(it.v==fa)
            continue;
        a[it.v]=a[u]^it.w;
        dfs1(it.v,u);
    }
}
void add(int x,int id){
    int now=1;
    for(int i=30;i>=0;i--){
        if(!trie[now][(1&(x>>i))])
            trie[now][(1&(x>>i))]=++tot;
        now=trie[now][(1&(x>>i))];
    }
    pos[now]=id;
    v[id].pb(x);
}
ll query(int x,int rt,int dep){
    ll res=1<<dep;
    for(int i=dep-1;i>=0;i--){
        int nex=trie[rt][(1&(x>>i))];
        if(!nex){
            nex=trie[rt][1^(1&(x>>i))];
            res|=(1<<i);
        }
        rt=nex;
    }
    return res;
}
void dfs(int rt,int dep){
    if(!rt||!dep)
        return ;
    int lson=trie[rt][0];
    int rson=trie[rt][1];
    dfs(lson,dep-1);
    dfs(rson,dep-1);
    if(!lson||!rson){///没有分支了,说明只剩一个集合了
        pos[rt]=pos[lson+rson];
        return ;
    }
    int rid=pos[rson],lid=pos[lson];
    if(v[rid].size()>v[lid].size()){
        swap(rid,lid);
        swap(rson,lson);
    }
    ll tmp=1<<30;
    int m=v[rid].size();
    for(int i=0;i<m;i++){
        tmp=min(tmp,query(v[rid][i],lson,dep-1));
        v[lid].pb(v[rid][i]);
    }
    v[rid].clear();
    ans+=tmp;
    pos[rt]=lid;
}
int main(){
    int n;
    scanf("%d",&n);
    for(int u,v,w,i=1;i<n;i++){
        scanf("%d%d%d",&u,&v,&w);
        u++,v++;
        g[u].pb(node{v,w});
        g[v].pb(node{u,w});
    }
    dfs1(1,0);
    sort(a+1,a+1+n);
    add(a[1],1);
    for(int i=2;i<=n;i++){
        if(a[i-1]!=a[i])
            add(a[i],i);
    }
    dfs(1,31);
    printf("%lld
",ans);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/starve/p/13409160.html