1 条题解

  • 0
    @ 2026-8-18 11:08:19

    还是很兴奋的。

    最近打 ABC 状态不咋好,这回搞了 55 题,还是很兴奋的。

    行吧!那就来讲讲这个题目吧!

    就是给你一个图,有 nn 个点,mm 条无向边,每条边呢还有一个权值。要你找到从 11nn 的所有简单路径中,经过的边的权值或值最小的。要求输出这个或值。

    首先可以打一个暴搜。肯定是对的,是吧,但是会超时。我赛时就是这样傻乎乎弄了一次,然后吃了一发罚时。

    考虑到是或运算,肯定是有问题的。普通的搜索肯定过不了。

    涉及到位运算,一般都是拆位,是吧?那就往这个方向想。

    我们从高位开始枚举。为什么不从低位开始?因为有一条显而易见的结论:如果当前这一位可以为 00,肯定是比当前这一位为 11 的答案优的。为啥啊,因为后面的所有都为 11 也超不过现在这一位为 11

    那就行了。从高位开始枚举,尝试让最终答案的这一位填上 00。那咋整?并查集!

    我们枚举每一条边,如果这个边的权值 ww 在当前枚举到的这一位上确实是 00,我们就可以用并查集把这个边连接的两个点弄到一个集合里去。

    枚举完了,我们就判断一下,11nn 是不是联通的。如果是,那么这一位就可以为 00;不是的话,这一位就只能是 11 咯,那 ansans 就要加上这一位为 11 的答案了。

    最后输出就可以了。

    编起来很简单的,但还是附一份赛时代码吧。

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 2e5+5;
    struct line{int u,v,w;}ln[N];
    int n,m,ans,fa[N];bool is[N];
    int FF(int u){return (fa[u]==u?u:fa[u]=FF(fa[u]));}
    void Merge(int u,int v){fa[FF(v)]=FF(u);return;}
    int main(){
        cin>>n>>m;
        for(int i=1;i<=m;i++)cin>>ln[i].u>>ln[i].v>>ln[i].w;
        for(int x=29;x>=0;x--){
            for(int i=1;i<=n;i++)fa[i]=i;
            for(int i=1;i<=m;i++){
                if((ln[i].w>>x)&1)continue;bool OK=1;
                for(int o=29;o>x;o--)if(!is[o]&&((ln[i].w>>o)&1))OK=0;
                if(!OK)continue;
                if(FF(ln[i].u)!=FF(ln[i].v))Merge(ln[i].u,ln[i].v);
            }
            if(FF(1)!=FF(n))is[x]=1,ans|=(1<<x);
        }
        cout<<ans<<"\n";
        return 0;
    }
    

    如果觉得本篇题解还不错的话,麻烦你点一个小小的赞,万分感谢!

    • 1

    *【并查集】最小或路径[ABC408E] Minimum OR Path

    信息

    ID
    855
    时间
    1000ms
    内存
    256MiB
    难度
    9
    标签
    递交数
    115
    已通过
    11
    上传者