Bitwise Exclusive-OR Sequence
题意:
有n个点, m个关系 每个关系 a b c 表示点a的值 异或 点b的值,为c
分析
首先可能是多个图, 对于每个图中的每一位, 取0 或者取1 都是可以确定图上的其他数字取0 或者取1 。 所以我们可以去枚举取0 或者取1 ,来取个min 得到结果。
所以这里我们用并查集, 最大数为 2的30次, 所以我们对于每一位都做一个并查集, 就是30个并查集。 f[a] 表示当前位置取1 f[a+n] 表示当前位取0
这样就可以枚举区间了。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5+10;
LL n, m, fa[N], sz[N];
LL a[N];
struct Node
{
LL a, b;
LL val;
}num[N];
LL find(LL x)
{
if(fa[x] != x) fa[x] = find(fa[x]);
return fa[x];
}
void init()
{
for(LL i = 1; i <= n; i ++)
{
fa[i] = i, sz[i] = 1;
fa[i+n] = i+n, sz[i+n] = 0;
}
}
void merge(LL a, LL b)
{
sz[a] += sz[b];
fa[b] = a;
}
int main()
{
cin >> n >> m;
for(int i = 1; i <= m; i ++)
{
scanf("%lld%lld%lld", &num[i].a, &num[i].b, &num[i].val);
}
LL res = 0;
for(int i = 0; i < 30; i ++)
{
init(); // 每一次做并查集都要初始化!
for(int j = 1; j <= m; j ++)
{
int aa = find(num[j].a);
int bb = find(num[j].b);
int aaa = find(num[j].a + n);
int bbb = find(num[j].b + n);
if((num[j].val >> i) & 1 ) // 不同为1 ,一个取0一个取1
{
if(aa == bb)
{
cout << -1 << endl;
return 0;
}
if(aa == bbb) continue;
merge(aa, bbb);
merge(bb, aaa);
}
else // 相同为0, 都取1 或者都取0
{
if(aa == bbb )
{
cout << -1 << endl;
return 0;
}
if(aa == bb) continue;
merge(bb, aa);
merge(bbb, aaa);
}
}
for(int j = 1; j <= n; j ++) // 对于每个数字计算结果
{
res += (LL)min(sz[find(j)], sz[find(j+n)]) * (1 << i);
sz[find(j)] = 0;
sz[find(j+n)] = 0;
}
}
cout << res << endl;
return 0;
}
/*
3 3
1 2 1
2 3 1
1 3 1
*/