解题思路


图片说明 ,这道题目看题解才看出来的,先看边权图片说明 其实不好操作,那么我们可以调整一下,一条边连接2个点,把边权,改成它连接2点的异或值,一个环的异或值需要为0,对于环中的点,开头的点任意取1,或者0,对于整个环的异或值图片说明 =0恒成立。

图片说明

所以对于连通块,首先对于给定0,1值的边,保存起来,通过我们转换点值的定义,去先把这些连通值处理,如果存在冲突,即无解,直接输出0,程序结束。
否则只剩下边权为-1的边,值确定的边可以添加到连通块。
情况1、这条边在一个连通块中充当环中最后一条边,那么这条边就可以通过前面的值以及边权异或值为0,唯一确定。
情况2、这条边是连通另外一个连通块,可能只有一个元素或者一个多个元素,这样的化这条边可取0/1两个值,对应后面的情况为知边,直接跟着取反,保证异或值仍为0。
连通块通过并查集处理,中途退出图片说明 函数,这样一条条边去把连通块连接起来,最终变成一个连通块,方案数就是答案。注意开到图片说明 ,说的可能不是很清楚,图比较好理解。


https://ac.nowcoder.com/acm/contest/view-submission?submissionId=43555625&returnHomeType=1&uid=919749006


#include <bits/stdc++.h>
using namespace std;
#define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
typedef long long ll;

inline int read() {
    int s = 0, w = 1; char ch = getchar();
    while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); }
    while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
    return s * w;
}
const int N = 1e5 + 7;
const int MOD = 998244353;
struct Node {
    int v;
    int cost;
};
vector<Node> e[N];
int u[N], v[N], w[N];
int father[N], fatheri;
int val[N];
int n, m;

int find(int root) {
    int son = root;
    while (root != father[root])
        root = father[root];
    while (son != root) {
        int temp = father[son];
        father[son] = root;
        son = temp;
    }
    return root;
}

void merge(int a, int b) {
    int fa = find(a);
    int fb = find(b);
    if (fa != fb) {
        father[fa] = fb;
    }
}

void dfs(int x) {
    father[x] = fatheri;
    for (auto it : e[x]) {
        int v = it.v, w = it.cost;
        if (father[v] && (val[v] ^ val[x]) != w) { //存在和我们定义填涂冲突节点
            puts("0");
            exit(0);  // 让程序正常运行结束
        }
        if (father[v])  continue;
        val[v] = val[x] ^ w;
        dfs(v);
    }
}

int main() {
    n = read(), m = read();
    for (int i = 1; i <= m; ++i) {
        u[i] = read(), v[i] = read(), w[i] = read();
        if (~w[i]) { // w[i]!=-1,存在已知边权值,方案已经固定为1
            e[u[i]].push_back(Node{ v[i],w[i] });
            e[v[i]].push_back(Node{ u[i],w[i] });
        }
    }
    for (int i = 1; i <= n; ++i) {
        if (!father[i]) {
            fatheri = i;  // 把环内元素父亲都定义为i
            dfs(i); // 对环进行赋值
        }
    }
    ll ans = 1; //取模不开ll,容易流泪 +_+
    for (int i = 1; i <= m; ++i) {
        if (father[find(u[i])] != father[find(v[i])]) {  //不在同一个环中,存在2种填涂方案
            ans = (ans << 1) % MOD;
            merge(u[i], v[i]);
        }
    }
    printf("%lld\n", ans);
    return 0;
}