2020牛客暑期多校训练营(第五场)B-Graph

Graph

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

题目大意

给一棵树,每条边有边权。可以任意加边和删边,但要满足任何时刻图连通,而且任何一个环的边权异或和为0。求操作后最小权值和。

解题思路

任意两个点之间连边的权值都是固定的,由于图需要始终联通,所以两点间始终存在至少一条路径,如果存在多条,根据环的异或和为0,两点间的路径的异或和应该相等,且始终是固定的。(摘自官方题解)

这样么,就可以每个点都记录一个权值,而两点间连边的权值,就是两端点权值的异或值。
接下来就是求异或最小生成树的问题了,使用Boruvka算法来解决是一种很吼的选择(学到了新的算法)。

Boruvka以及其他最小生成树算法:https://www.iteye.com/blog/dsqiu-1689178

而要让异或和最小,就要让二进制高位尽可能相等。
这样可以用到字典树来解决,连接两个点时,在这个节点的子树中找异或后最小的点对;为了保证得到的异或结果尽可能小,向下考虑走向时尽量方向相同。

AC代码

#include<bits/stdc++.h>
using namespace std;
struct link
{
    int x,y,z;
} e[200010];
int a[200010],b[6000010],c[6000010],d[100010],v[6000010][2],m[30],s=1,tot;
long long ans;
void get(int x,int y)
{
    for(int i=d[x];i;i=e[i].y)
        if(e[i].x!=y)
        {
            a[e[i].x]=a[x]^e[i].z;
            get(e[i].x,x);
        }
}
long long find(int x,int y)
{
    if(c[x]==30) return a[b[x]]^a[b[y]];
    bool f=0;
    long long z=2e9;
    if(v[x][0] && v[y][0]) z=min(z,find(v[x][0],v[y][0])),f=1;
    if(v[x][1] && v[y][1]) z=min(z,find(v[x][1],v[y][1])),f=1;
    if(!f)
    {
        if(v[x][0] && v[y][1]) z=min(z,find(v[x][0],v[y][1]));
        else if(v[x][1] && v[y][0]) z=min(z,find(v[x][1],v[y][0]));
    }
    return z;
}
void dfs(int x)
{
    if(!x) return;
    dfs(v[x][0]);dfs(v[x][1]);
    if(v[x][0] && v[x][1]) ans+=find(v[x][0],v[x][1]);
}
int main()
{
    int n,x,y,z,i,j;
    bool f;
    b[1]=m[0]=1;
    for(i=1;i<=29;i++)
        m[i]=m[i-1]*2;
    scanf("%d",&n);
    for(i=1;i<n;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        x++,y++;
        e[++tot].x=y,e[tot].z=z,e[tot].y=d[x],d[x]=tot;
        e[++tot].x=x,e[tot].z=z,e[tot].y=d[y],d[y]=tot;
    }
    get(1,0);
    for(i=1;i<=n;i++)
    {
        x=1;
        for(j=29;j>=0;j--)
        {
            y=1<<j,f=y&a[i];
            if(!v[x][f]) v[x][f]=++s,c[s]=29-j+1,b[s]=n+1;
            x=v[x][f];
        }
        b[x]=i;
    }
    dfs(1);
    printf("%lld\n",ans);
    return 0;
}
2020牛客暑期多校训练营 文章被收录于专栏

只是题解,可参考,可学习,可点赞:)

全部评论

相关推荐

程序员小白条:找的太晚,别人都是大三实习,然后大四秋招春招的,你大四下了才去实习,晚1年
点赞 评论 收藏
分享
来个厂收我吧:首先,市场侧求职我不是很懂。 但是,如果hr把这份简历给我,我会觉得求职人不适合做产品经理。 问题点: 1,简历的字体格式不统一,排版不尽如人意 2,重点不突出,建议参考star法则写个人经历 3,印尼官方货币名称为印度尼西亚卢比(IDR),且GMV690000印尼盾换算为305人民币,总成交额不高。 4,右上角的意向职位在发给其他公司时记得删除。 5,你所有的经历都是新媒体运营,但是你要投市场营销岗位,jd和简历不匹配,建议用AI+提示词,参照多个jd改一下经历内容。 修改建议: 1,统一字体(中文:思源黑体或微软雅黑,英文数字:time new romans),在word中通过表格进行排版(b站学) 2,校招个人经历权重:实习经历=创业经历(大创另算)>项目经历>实训经历>校园经历 3,请将项目经历时间顺序改为倒序,最新的放最上方。 4,求职方向不同,简历文字描述侧重点也需要不同。
点赞 评论 收藏
分享
评论
4
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务