列表

详情


NC50365. Tree

描述

给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有条白色边的生成树。题目保证有解。

输入描述

第一行分别表示点数,边数和需要的白色边数。
接下来E行,每行表示这边的端点(点从0开始标号),边权,颜色(0白色,1黑色)。

输出描述

一行表示所求生成树的边权和。

示例1

输入:

2 2 1
0 1 1 1
0 1 2 0

输出:

2

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 95ms, 内存消耗: 1984K, 提交时间: 2019-12-27 10:12:44

#include<bits/stdc++.h>
using namespace std;

const int MAXN = 5e4+3;
int V, E, need;

struct Edge {
  int s, t, c, col;
};
vector<Edge> edges;

int p[MAXN];
int find(int x) {
  return p[x] = p[x] == x? x: find(p[x]);
}
pair<int, long long> gao(int acc) {
  for (auto &e: edges) if (e.col == 0) e.c += acc;
  long long tot = 0;
  int cnt = 0;
  for (int i = 0; i < V; i++) p[i] = i;

  sort(edges.begin(), edges.end(), [](const Edge &a, const Edge &b) {
    if (a.c == b.c) return a.col < b.col;
    return a.c < b.c;
  });

  for (auto &e: edges) {
    int x = e.s, y = e.t;
    int px = find(x), py = find(y);
    if (px == py) continue;
    p[px] = py;
    tot += e.c;
    if (e.col == 0) cnt++;
  }
  for (auto &e: edges) if (e.col == 0) e.c -= acc;
  return {cnt, tot};
}

int main() {
  ios_base::sync_with_stdio(false);
  cin >> V >> E >> need;
  edges.resize(E); for (auto &e: edges) cin >> e.s >> e.t >> e.c >> e.col;

  int lo = -128, hi = 128;
  while (lo < hi) {
    int mid = (lo + hi + 256) / 2 - 128;
    auto tmp  = gao(mid);
    if (tmp.first >= need) lo = mid + 1;
    else hi = mid;
  }
  cout << gao(hi-1).second - need * (hi - 1) << endl;
}

C++ 解法, 执行用时: 113ms, 内存消耗: 3452K, 提交时间: 2022-06-19 11:12:01

#include<bits/stdc++.h>
using namespace std;
struct edge
{
	long long x,y,d,c;
}E[100010];
long long n,m,need;
long long ans,fa[100010];
long long tot,white,anss;
int find(int x)
{
	if(x==fa[x])return x;
	return fa[x]=find(fa[x]);
}
int cmp(edge a,edge b)
{
	if(a.d==b.d)return a.c<b.c;
	return a.d<b.d;
}
int kk(int x)
{
	for(int i=0;i<=n;i++)
	fa[i]=i;
	for(int i=1;i<=m;i++)
	if(!E[i].c)
	E[i].d+=x;
	sort(E+1,E+m+1,cmp);
	ans=0,tot=0,white=0;
	for(int i=1;i<=m;i++)
	{
		int f1=find(E[i].x),f2=find(E[i].y);
		if(f1==f2)
		continue;
		fa[f1]=f2;
		tot++;
		ans+=E[i].d;
		white+=(!E[i].c);
		if(tot==n-1)break;
	}
	for(int i=1;i<=m;i++)
	if(!E[i].c)E[i].d-=x;
	if(white>=need)
	return 1;
	return 0;
}
int main()
{
	cin>>n>>m>>need;
	for(int i=1;i<=m;i++)
	cin>>E[i].x>>E[i].y>>E[i].d>>E[i].c;
	int l=-101,r=101;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(kk(mid))
		{
			l=mid+1;
			anss=ans-need*mid;
		}
		else r=mid-1;
	}
	cout<<anss<<endl;
}

上一题