[ARC093E] Bichrome Spanning Tree
[题目链接]
https://atcoder.jp/contests/arc093/tasks/arc093_c
[题解]
一个重要的观察是 : 最多只会用一条不在忽略颜色求得的最小生成树上的边。
首先不妨求出最小生成树 , 并计算其权值 \(W\) , 令 \(\delta = X - W\)。
若 \(\delta < 0\) , 则答案为 \(0\)。
否则不妨求出加入一条边后生成树权值比 \(W\) 小 , 等于 \(W\) , 大于 \(W\) 的边数 , 分别为 \(c0 , c1 , c2\)。
若 \(\delta = 0\) , 说明要么原最小生成树就合法 , 要么满足有一条可替换的边 , 答案为 \((2 ^ {N - 1} - 2) \cdot 2 ^ {M - N + 1} + 2 \cdot (2 ^ {c1} - 1) \cdot 2 ^ {c2}\)。
若 \(\delta > 0\) , 说明最小生成树同色 , 且能找到一条可替换的边 , 答案为 \(2 \cdot 2 ^ {c2} \cdot (2 ^ {c1} - 1)\)。
时间复杂度 : \(O((N + M)logN)\)
[代码]
#include<bits/stdc++.h>
using namespace std;
#define rep(i , l , r) for (int i = (l); i < (r); ++i)
typedef long long LL;
const int MN = 2e5 + 5 , MM = 4e5 + 5 , mod = 1e9 + 7;
struct Edg {
int to; LL w; int nxt;
} E[MM << 1];
struct Edge {
int u , v; LL w;
} A[MM << 1];
int N , M , dest , fa[MN] , two[MM] , tot , head[MN] , use[MN];
LL X , mx;
inline void add(int u , int v , LL w) {
E[++tot] = (Edg) {v , w , head[u]}; head[u] = tot;
E[++tot] = (Edg) {u , w , head[v]}; head[v] = tot;
}
inline void get(int u , int lst , LL mv) {
if (u == dest) { mx = mv; return; }
for (int i = head[u]; i; i = E[i].nxt) {
int v = E[i].to; if (v == lst) continue;
get(v , u , max(mv , E[i].w));
}
}
inline LL query(int u , int v) {
dest = v;
get(u , 0 , 0);
return mx;
}
inline int find(int x) {
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
inline bool cmp(Edge a , Edge b) {
return a.w < b.w;
}
inline bool mg(int u , int v) {
if (find(u) == find(v)) return false;
fa[find(u)] = find(v); return true;
}
int main() {
scanf("%d%d%lld" , &N , &M , &X);
two[0] = 1;
for (int i = 1; i <= M; ++i) two[i] = 2ll * two[i - 1] % mod;
for (int i = 1; i <= M; ++i) scanf("%d%d%lld" , &A[i].u , &A[i].v , &A[i].w);
sort(A + 1 , A + 1 + M , cmp);
for (int i = 1; i <= N; ++i) fa[i] = i;
LL ans = 0;
for (int i = 1; i <= M; ++i) if (mg(A[i].u , A[i].v)) add(A[i].u , A[i].v , A[i].w) , ans += (LL) A[i].w , use[i] = 1;
int c0 = 0 , c1 = 0 , c2 = 0;
LL d = X - ans;
if (d < 0) {
puts("0");
return 0;
}
for (int i = 1; i <= M; ++i) if (!use[i]) {
int t = A[i].w - query(A[i].u , A[i].v);
if (t > d) ++c2;
else if (t == d) ++c1;
else ++c0;
}
if (d == 0) printf("%d\n" , (1ll * (two[N - 1] - 2 + mod) % mod * two[M - N + 1] % mod + 2ll * (1ll * (two[c1] - 1) * two[c2] % mod + mod) % mod) % mod);
else printf("%d\n" , (2ll * two[c2] % mod * ((two[c1] - 1) % mod + mod) % mod) % mod);
return 0;
}