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牛客暑期多校训练营 文章被收录于专栏

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

全部评论

相关推荐

07-24 19:01
门头沟学院 Java
后天笔试,又要开始做题了
Sairus:明天10:00笔试
投递京东等公司10个岗位
点赞 评论 收藏
分享
程序员小白条:这比例牛逼,750:1
点赞 评论 收藏
分享
机械打工仔:不管啥专业,找工作改简历的第一课先把你那排版改了,简历上不要写个人简历四个字,找你要简历的谁不知道这个是简历?而且还占那么多空间,直接把自己名字和基础信息写上面,整体字体大一些。 还有这种经典两页简历一页大空白,导出PDF的时候多了一页几乎全是白的你自己看着不难受吗随手的事为啥不能改掉呢,这是态度问题,你试想一下你是HR你打开简历看到格式都没调整过会是什么感受?你自己都不重视你的简历,HR更不会在意。 然后内容你那个做两年咖啡就别往里写了,简历在精不在多,你在往你的简历里打字的时候就要想好这东西对你要找的工作有没有帮助。自我评价写一行就行了,不如给专业技能单开一栏。核心课程均分90这个真别写了,把你上过的有用的专业课列出来也行。有很多地方废话很多的精炼一下,比如你校内项目第一个写的那些,全然没有重点。 好好修改一下,我看你内容也挺优秀的,别被一个随便做的简历耽误了,我一个同专业的打工人看了都揪心更别说一天看几百份简历的HR
听劝,我这个简历该怎么改...
点赞 评论 收藏
分享
不愿透露姓名的神秘牛友
07-24 13:32
点赞 评论 收藏
分享
评论
4
收藏
分享

创作者周榜

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