MinOr Tree(1900)位运算,或运算,贪心 Codeforces Round #764 (Div. 3)

G. MinOr Tree
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
Recently, Vlad has been carried away by spanning trees, so his friends, without hesitation, gave him a connected weighted undirected graph of 𝑛 vertices and 𝑚 edges for his birthday.

Vlad defined the ority of a spanning tree as the bitwise OR of all its weights, and now he is interested in what is the minimum possible ority that can be achieved by choosing a certain spanning tree. A spanning tree is a connected subgraph of a given graph that does not contain cycles.

In other words, you want to keep 𝑛−1 edges so that the graph remains connected and the bitwise OR weights of the edges are as small as possible. You have to find the minimum bitwise OR itself.

Input
The first line of the input contains an integer 𝑡 (1≤𝑡≤104) — the number of test cases in the input.

An empty line is written in front of each test case.

This is followed by two numbers 𝑛 and 𝑚 (3≤𝑛≤2⋅105,𝑛−1≤𝑚≤2⋅105) — the number of vertices and edges of the graph, respectively.

The next 𝑚 lines contain the description of the edges. Line 𝑖 contains three numbers 𝑣𝑖, 𝑢𝑖 and 𝑤𝑖 (1≤𝑣𝑖,𝑢𝑖≤𝑛, 1≤𝑤𝑖≤109, 𝑣𝑖≠𝑢𝑖) — the vertices that the edge connects and its weight.

It is guaranteed that the sum 𝑚 and the sum 𝑛 over all test cases does not exceed 2⋅105 and each test case contains a connected graph.

Output
Print 𝑡 lines, each of which contains the answer to the corresponding set of input data — the minimum possible spanning tree ority.

Example
inputCopy
3

3 3
1 2 1
2 3 2
1 3 2

5 7
4 2 7
2 5 8
3 4 2
3 2 1
2 4 2
4 1 2
1 2 2

3 4
1 2 1
2 3 2
1 3 3
3 1 4
outputCopy
2
10
3
Note
Graph from the first test case.
Ority of this tree equals to 2 or 2 = 2 and it’s minimal.
Without excluding edge with weight 1 ority is 1 or 2 = 3.

题意 :

  • 给一图,求其边权或和最小的生成树,并输出这个最小的边权或和

思路 :

  • 要求 或和 结果最小,因此树上边二进制高位尽可能为0
  • 因此,从最高位出发,判断在不选当前位为1的边的情况下是否能构成一棵树(同时也要舍弃已经被标记的边),若能,最终结果的二进制该位肯定为0,同时,标记舍弃当前这位为1的边
  • 复杂度 30 ∗ ( 2 ∗ 1 0 5 ) ∗ l o g ( 2 ∗ 1 0 5 ) 30*(2*10^5)*log(2*10^5) 30(2105)log(2105)
#include <iostream>
#include <cstring>
#include <vector>
#define endl '\n'
using namespace std;

const int N = 2e5 + 10;

int n, m;
int fa[N];
bool st[N];     // 1表示舍弃
struct Edge
{
    int a, b, w;
}edge[N];

int find(int x)
{
    if (x != fa[x]) fa[x] = find(fa[x]);
    return fa[x];
}

bool check(int x)
{
    for (int i = 1; i <= n; i ++ ) fa[i] = i;
    vector<int> ve;
    
    for (int i = 0; i < m; i ++ )
    {
        int a = edge[i].a, b = edge[i].b, w = edge[i].w;
        if (st[i]) continue;
        if (w >> x & 1) { ve.push_back(i); continue; }
        
        a = find(fa[a]), b = find(fa[b]);
        if (a != b) fa[a] = b;
    }
    
    int cnt = 0;
    for (int i = 1; i <= n; i ++ )
        if (fa[i] == i)
            cnt ++ ;
    
    if (cnt != 1) return false;
    for (auto v : ve) st[v] = true;
    
    return true;
}

void solve()
{
    cin >> n >> m;
    for (int i = 0, a, b, w; i < m && cin >> a >> b >> w; i ++ ) edge[i] = {a, b, w};
    
    memset(st, 0, sizeof st);
    
    int res = 0;
    for (int i = 30; i >= 0; i -- )
    {
        if (!check(i)) res |= (1 << i);     // false 1
    }
    
    cout << res << endl;
}

int main()
{
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    
    int _; cin >> _;
    while (_ -- )
        solve();
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值