[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;
}
posted @ 2021-01-24 16:08  evenbao  阅读(94)  评论(0编辑  收藏  举报