代码源 Div1 - 109#454. Minimum Or Spanning Tree(最小生成树,边权按位或,贪心,并查集) CF1624G

Posted 小哈里

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了代码源 Div1 - 109#454. Minimum Or Spanning Tree(最小生成树,边权按位或,贪心,并查集) CF1624G相关的知识,希望对你有一定的参考价值。

problem

solution

  • 题意:生成树的代价为他所有边的边权按位或得到的值,求最小生成树
  • 贪心,一般来说,求 按位与 和 按位或 的最大值都可以从高往低逐位的贪心处理
  • 对于当前位 b 而言,若存在 n−1 条边的边权都不存在 b 且不构成环的话,那么我们可以把所有包含 b 的边都删除;若不足 n−1 条边满足之前的条件的话,则将 b 加入答案
//AC1
#include<bits/stdc++.h>
using namespace std;

#define ios ios::sync_with_stdio(0), cin.tie(0),cout.tie(0)
typedef long long LL;
const LL maxn = 1e6+10;

int fa[maxn+10];
void init(int n)for(int i = 0; i <= n; i++)fa[i]=i;
int find(int x)return x==fa[x]?x:fa[x]=find(fa[x]);
void merge(int x, int y)x=find(x);y=find(y);if(x!=y)fa[x]=y;
int count(int n)int cnt=0; for(int i = 1; i <= n; i++)if(fa[i]==i)cnt++;return cnt;

struct nodeint u, v, w; e[maxn];
int vis[maxn];

int main()
    int n, m;  cin>>n>>m;
    for(int i = 1; i <= m; i++)
        cin>>e[i].u>>e[i].v>>e[i].w;
    
    int ans = 0;
    for(int b = 29; b >= 0; b--)
        init(n);
        int cc = 1;
        for(int i = 1; i <= m; i++)
            if(vis[i])continue;
            if((~e[i].w>>b) & 1)
                if(find(e[i].u)!=find(e[i].v))
                    merge(e[i].u, e[i].v);
                    cc++;
                
            
        
        if(cc == n)
            for(int i = 1; i <= m; i++)
                if((~e[i].w>>b) & 1)
                    
                else
                    vis[i] = 1;
                
            
        else
            ans |= 1<<b;
        
    
    cout<<ans<<"\\n";
    return 0;



//AC2
#include<bits/stdc++.h>
using namespace std;

#define IOS ios::sync_with_stdio(0), cin.tie(0),cout.tie(0)
typedef long long LL;
const LL maxn = 1e6+10;

int fa[maxn+10];
void init(int n)for(int i = 1; i <= n; i++)fa[i]=i;
int find(int x)return x==fa[x]?x:fa[x]=find(fa[x]);
void merge(int x, int y)x=find(x);y=find(y);if(x!=y)fa[x]=y;
int count(int n)int cnt=0; for(int i = 1; i <= n; i++)if(fa[i]==i)cnt++;return cnt;

tuple<int,int,int>e[maxn<<1];

int main()
    IOS;
    int n, m;  cin>>n>>m;
    for(int i = 1; i <= m; i++)
        cin>>get<0>(e[i])>>get<1>(e[i])>>get<2>(e[i]);
    
    int k = 29;
    int ans = (1<<k)-1;
    for(int i = k-1; i >= 0; i--)
        init(n);
        int cc = n;
        ans ^= (1<<i);
        for(int j = 1; j <= m; j++)
            if((get<2>(e[j])|ans)==ans && find(get<0>(e[j]))!=find(get<1>(e[j])))
                merge(get<0>(e[j]), get<1>(e[j]));
                cc--;
            
        
        ans ^= ((int)(cc!=1)<<i);
    
    cout<<ans<<"\\n";
    return 0;



以上是关于代码源 Div1 - 109#454. Minimum Or Spanning Tree(最小生成树,边权按位或,贪心,并查集) CF1624G的主要内容,如果未能解决你的问题,请参考以下文章

代码源 Div1 - 101#61. 二分答案(贪心)

代码源 Div1 - 105#451. Dis(倍增求LCA)

代码源 Div1 - 101#61. 二分答案(贪心)

代码源 Div1 - 107#452. 序列操作(思维)CF1198B

代码源 Div1 - 102#323. 最长因子链(dp)

代码源 Div1#104no crossing,Codeforces 793D,2100分,区间dp