G. Xor-matic Number of the Graph
题意:
给定一个无向图,一个interesting的三元环(u,v,s)满足,从u到v的路径上的异或和等于s,三元环的权值为s,求所有三元环权值之和。
分析:
求出所有的三元环,建立线性基,然后逐位求每一位的贡献。
代码:
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<cctype> #include<set> #include<queue> #include<vector> #include<map> using namespace std; typedef long long LL; inline LL read() { LL x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; } const int N = 100005, mod = 1e9 + 7; struct Edge{ int to, nxt; LL w; } e[500005]; int head[N], En; LL dis[N], b[65], mi[N], Ans; bool vis[N]; vector<LL> B; vector<int> A; inline void add_edge() { int u = read(), v = read(); LL w = read(); ++En; e[En].to = v, e[En].w = w; e[En].nxt = head[u]; head[u] = En; ++En; e[En].to = u, e[En].w = w; e[En].nxt = head[v]; head[v] = En; } void dfs(int u) { A.push_back(u); vis[u] = 1; for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (vis[v]) B.push_back(dis[u] ^ e[i].w ^ dis[v]); else { dis[v] = dis[u] ^ e[i].w; dfs(v); } } } void Insert(LL x) { for (int i = 60; ~i; --i) { if ((x >> i) & 1) { if (b[i]) x ^= b[i]; else { b[i] = x; break; } } } } void Clear() { memset(b, 0, sizeof(b)); A.clear(), B.clear(); } inline void mul(LL &x,LL y) { x *= y; x %= mod; } inline void add(LL &x,LL y) { x += y; if (x >= mod) x -= mod; } void Calc() { for (int i = 0; i < (int)B.size(); ++i) Insert(B[i]); LL cnt[2] = {0, 0}, r = 0, now; for (int i = 60; ~i; --i) if (b[i]) r ++; for (int k = 60; ~k; --k) { bool flag = 0; cnt[0] = cnt[1] = 0; for (int i = 60; ~i; --i) if ((b[i] >> k) & 1) flag = 1; for (int i = 0; i < (int)A.size(); ++i) cnt[(dis[A[i]] >> k) & 1] ++; now = cnt[0] * (cnt[0] - 1) / 2 + cnt[1] * (cnt[1] - 1) / 2; now %= mod; if (flag) { if (r >= 1) mul(now, mi[r - 1]); mul(now, mi[k]); add(Ans, now); } now = cnt[0] * cnt[1]; if (flag) { if (r >= 1) mul(now, mi[r - 1]); } else mul(now, mi[r]); mul(now, mi[k]); add(Ans, now); } Clear(); } int main() { int n = read(), m = read(); mi[0] = 1; for (int i = 1; i <= 62; ++i) mi[i] = mi[i - 1] * 2 % mod; for (int i = 1; i <= m; ++i) add_edge(); for (int i = 1; i <= n; ++i) { if (!vis[i]) { dfs(i); Calc(); } } cout << Ans; return 0; }