题解 [ARC093C] Bichrome Spanning Tree

传送门

赛时基本没有想这个题
所以把最水的题弃了
但是为啥 puts("0"); 有 31pts 啊?

要求染色后最小的包含两种颜色的边的生成树权值为 \(x\)
先去掉这个限制把最小生成树建出来
发现此时加入一条权为 \(w\) 的边 \((u, v)\) 会使权值增加 \(w-\max\{w_i \mid e_i\in path_{u, v}\}\)
发现要找最小生成树,那么发现符合要求的树至多是最小生成树上改一条边
有了这个结论就好做了
最小生成树上的边必须同色
\(cost_i\) 为加入边 \(i\) 会使权值增加多少
那么按 \(cost\) 排序后若要加边 \(i\),则排名比 \(i\) 小的必须与最小生成树同色
排名比 \(i\) 大的可以随便填
特别注意最小生成树权值等于 \(x\) 时要额外贡献一个生成树上也随便填的方案数
复杂度可以 \(O(nm)\sim O(m\log m)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define fir first
#define sec second
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline ll read() {
	ll ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m;
bool intr[N];
const ll mod=1e9+7;
ll val[N], cst[N], x, ans, sum;
struct tpl{int u, v, w;}sta[N];
struct edge{int to, next; ll val;}e[N<<1];
int head[N], dep[N], dsu[N], back[N], ecnt, top;
inline bool operator < (tpl a, tpl b) {return a.w<b.w;}
inline int find(int p) {return dsu[p]==p?p:dsu[p]=find(dsu[p]);}
inline void add(int s, int t, ll w) {e[++ecnt]={t, head[s], w}; head[s]=ecnt;}
inline ll qpow(ll a, ll b) {ll ans=1; for (; b; a=a*a%mod,b>>=1) if (b&1) ans=ans*a%mod; return ans;}

void dfs(int u, int fa) {
	for (int i=head[u],v; ~i; i=e[i].next) {
		v = e[i].to;
		if (v==fa) continue;
		back[v]=u;
		dep[v]=dep[u]+1;
		val[v]=e[i].val;
		dfs(v, u);
	}
}

ll qmax(int u, int v) {
	ll ans=0;
	while (u!=v) {
		if (dep[u]<dep[v]) swap(u, v);
		ans=max(ans, val[u]);
		u=back[u];
	}
	return ans;
}

signed main()
{
	// freopen("b.in", "r", stdin);
	// freopen("b.out", "w", stdout);

	n=read(); m=read(); x=read();
	memset(head, -1, sizeof(head));
	for (int i=1; i<=n; ++i) dsu[i]=i;
	for (int i=1,u,v,w; i<=m; ++i) {
		u=read(); v=read(); w=read();
		sta[i]={u, v, w};
	}
	sort(sta+1, sta+m+1);
	for (int i=1,s,t; i<=m; ++i) if ((s=find(sta[i].u))!=(t=find(sta[i].v))) {
		dsu[s]=t; sum+=sta[i].w; intr[i]=1;
		add(sta[i].u, sta[i].v, sta[i].w);
		add(sta[i].v, sta[i].u, sta[i].w);
	}
	dep[1]=1; dfs(1, 0);
	if (sum==x) ans=(ans+(qpow(2, n-1)-2)*qpow(2, m-n+1))%mod;
	for (int i=1; i<=m; ++i) if (!intr[i]) cst[++top]=sta[i].w-qmax(sta[i].u, sta[i].v);
	sort(cst+1, cst+top+1);
	for (int i=1; i<=top; ++i) if (sum+cst[i]==x) ans=(ans+qpow(2, top-i+1))%mod;
	printf("%lld\n", (ans%mod+mod)%mod);
	
	return 0;
}
posted @ 2022-06-10 17:21  Administrator-09  阅读(0)  评论(0编辑  收藏  举报