【Nowcoder】2020牛客暑期多校训练营(第五场)B-graph | 最小异或生成树

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

题目大意:

给你一棵树,你可以删除一些边或者增加一些边,但是在过程中必须保证图联通并且出现的任何一个环的异或和为0

题目思路:

考虑加边成为完全图

那么 如何做到加边过程中 做到出现的环为0呢?

考虑从任意一个根出发,到达u的异或和为x,到达v的异或和为y

那么 u 与 v之间的异或和即为 x^y

所以说只需要在u与v之间增加权值为x^y的边

这样就可以保证上述两个条件并且成为完全图

之后就可以求最小异或生成树了

至于求最小异或生成树,详见:https://blog.csdn.net/qq_43857314/article/details/107645865

Code:

ll n,m,p;
ll a[Maxn];
struct XorTrie{
    int dfn = 0;
    int t[maxn][2];
    int L[maxn],R[maxn];
    void _init(){dfn = 0;}
    void Insert(ll x,int id){
        int rt = 0;
        for(int k=32;k>=0;k--){
            int op = (x>>k&1ll)?1:0;
            if(!t[rt][op]) t[rt][op] = ++dfn;
            rt = t[rt][op];
            if(!L[rt]) L[rt] = id;
            R[rt] = id;
        }
    }
    ll AnswerPos(int rt,int pos,ll x){
        ll ans = 0;
        for(int i=pos;i>=0;i--){
            int op = (x>>i&1ll)?1:0;
            if(t[rt][op]) rt = t[rt][op];
            else{
                rt = t[rt][!op];
                ans += (1ll<<i);
            }
        }return ans;
    }
    void Traceback(int rt){
        printf("%d %d\n",L[rt],R[rt]);
        if(t[rt][0]) Traceback(t[rt][0]);
        if(t[rt][1]) Traceback(t[rt][1]);
    }
    ll Divide(int rt,int pos){
        if(t[rt][0]&&t[rt][1]){
            int x = t[rt][0],y = t[rt][1];
            ll minl = INF;
            for(int k=L[x];k<=R[x];k++) minl = min(minl,AnswerPos(y,pos-1,a[k])+(1ll<<pos));
            return minl+Divide(t[rt][0],pos-1)+Divide(t[rt][1],pos-1);
        }
        else if(t[rt][0]) return Divide(t[rt][0],pos-1);
        else if(t[rt][1]) return Divide(t[rt][1],pos-1);
        return 0;
    }
}tire;
struct node{
    int e,next;
    ll w;
}edge[Maxn];
int head[Maxn];
ll cnt = 2;
void addedge(int u,int v,ll w){
    edge[cnt] = node{v,head[u],w};
    head[u] = cnt++;
}
void dfs(int u,int fa,ll w){
    a[u] = w;
    for(int i=head[u];i;i=edge[i].next){
        int e = edge[i].e;
        if(e == fa) continue;
        dfs(e,u,w^edge[i].w);
    }
}
int main()
{
    tire._init();
    read(n);
    for(int i=1;i<=n-1;i++){
        ll x,y,w;read(x);read(y);read(w);
        x++;y++;
        addedge(x,y,w);
        addedge(y,x,w);
    }
    dfs(1,1,0);
    sort(a+1,a+n+1);
    for(int i=1;i<=n;i++) tire.Insert(a[i],i);
    printf("%lld\n",tire.Divide(0,32));
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43857314/article/details/107645765