NKOJ全TJ计划——NP11744

题目内容

[20241017] Min-max 容斥

小 M 在\(\pi\) 岁时学会了 min-max 容斥。

给定一张 \(n\)个点\(m\)条边的边带权简单连通无向图。现需要将其的每个结点染成黑色或白色。

定义两个结点的距离为这两点间所有路径的边权之和的最小值。

对于一种染色的方式,定义一个结点\(u\) 的代价为:对于所有与\(u\) 异色的点\(v\)\(u\)\(v\) 的距离的最小值。如果不存在这样的点,那么代价为\(10^{100}\)

该染色方式的代价为所有结点的代价的最大值。

您需要构造一种染色方式,使其最小化代价。

\(2\le n\le 5\times 10^5,n-1\le m\le\min(5\times 10^5,\frac{n(n-1)}2),1\le w\le 10^9,1\le u,v\le n\)

思路

最小生成树。
首先考虑当输入为一棵树的情况:显然,为了使代价最小,我们应该采取“交替染色”的策略,即每一个旁边的都跟他本身不一样。
所以我们可以想到,我们可以召唤一棵树。
为了使最大的最小,显然我们应该召唤最小生成树。
为什么呢?因为如果我们在两个0点召唤一条边,那它并不会使答案更优。
如果在0和1之间加一条边,如果它会使答案更优,我们早就加入它了。所以只剩不变或更恶劣的情况。
然后就没有然后了。

代码

#include<bits/stdc++.h>
//#pragma GCC optimize("O3,unroll-loops")感谢章鱼的核聚变
//#pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt")让我WA 0还找不到问题
using namespace std;
struct bi{
	int u,v,w;
}a[500004];
int n,m,i,j,x,y,z,c[500004],p[500004],ans;
vector<int> v[500004];
void dfs(int x,int y){
	c[x]=y;
	for(int i=0;i<v[x].size();i++){
		if(c[v[x][i]]) continue;
		dfs(v[x][i],3-y);
	}
	return ;
}
bool cmp(bi q,bi w){
	return q.w<w.w;
}
int f(int x){
	if(p[x]==x) return x;
	return p[x]=f(p[x]);
}
int main()
{
//	freopen("A4.in","r",stdin);
//	freopen("A4.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++) p[i]=i;
	for(i=1;i<=m;i++) scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
	sort(a+1,a+1+m,cmp);
	for(i=1;i<=m;i++){
		if(f(a[i].u)==f(a[i].v)) continue;
		p[f(a[i].u)]=f(a[i].v);
		v[a[i].u].push_back(a[i].v);
		v[a[i].v].push_back(a[i].u);
	}
	dfs(1,1);
	for(i=1;i<=n;i++) printf("%d",c[i]-1);
}
posted @ 2025-10-05 17:07  哈利·波特  阅读(19)  评论(0)    收藏  举报