专栏文章

题解:P13736 [JOIGST 2025] 日本浮现 / Japan Emerges

P13736题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@min5wmxq
此快照首次捕获于
2025/12/01 21:05
3 个月前
此快照最后确认于
2025/12/01 21:05
3 个月前
查看原文
看到这种带有至少字样的题目,我们的第一反应应该是二分答案最小生成树!
没错,这题是一道最小生成树的题目,关键在于建边。
不难发现,对于一个点 (x,y)(x,y),它可以联通的点只能是左边一列、当前列、右边一列上的点,这里用二分查找就可以了。为了保证不重复连边,每个点只连向更深的点。
那么边权呢?
我们分类讨论一下,设当前点为 (xa,ya)(x_a,y_a),找到的点为 (xb,yb)(x_b,y_b),找到的点纵坐标更大。画图发现,对于左右两列的点,只要过了 (xbxa)(x_b - x_a) 天,它们就联通,对于同一列的点,过了 (xbxa1)(x_b - x_a -1) 天,它们就联通。
那么边权就是上面说的三种,套一个克鲁斯卡尔板子就可以过了。

代码

CPP
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define V vector
#define FOR(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define pb push_back
const int INF=1e9+10;
using T=array<int,3>;
using P=array<int,2>;
struct node{int x,y;};
int read(){
	int x=0,f=1;
	char c=getchar();
	while(c>'9'||c<'0'){
		if(c=='-') f=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9'){
		x=(x<<3)+(x<<1)+c-48;
		c=getchar();
	}
	return x*f;
}
signed main(){
	int h=read(),w=read(),n=read();
	V<V<P> >mp(w+2);
	V<node>a(n+1);
	FOR(i,1,n)a[i].x=read(),a[i].y=read(),mp[a[i].y].pb({a[i].x,i});
	FOR(i,1,w) sort(mp[i].begin(),mp[i].end());
	V<int>fa(n+1);iota(fa.begin(),fa.end(),0);
	auto fin=[&](int x){
		while(x^fa[x]) x=fa[x]=fa[fa[x]];
		return x;
	};
	V<T>e;
	FOR(i,1,n){
		auto it=lower_bound(mp[a[i].y].begin(),mp[a[i].y].end(),P{a[i].x+1,0});
		if(it!=mp[a[i].y].end()){
			auto t1=*it;
			e.pb({t1[0]-a[i].x-1,i,t1[1]});
		}
		if(!mp[a[i].y-1].empty()){
			it=lower_bound(mp[a[i].y-1].begin(),mp[a[i].y-1].end(),P{a[i].x,0});
			if(it!=mp[a[i].y-1].end()){
				auto t1=*it;
				e.pb({t1[0]-a[i].x,i,t1[1]});
			}
		}
		if(!mp[a[i].y+1].empty()){
			it=lower_bound(mp[a[i].y+1].begin(),mp[a[i].y+1].end(),P{a[i].x,0});
			if(it!=mp[a[i].y+1].end()){
				auto t1=*it;
				e.pb({t1[0]-a[i].x,i,t1[1]});
			}
		}
	}
	int tot=0;
	sort(e.begin(),e.end());
	for(auto i:e){
		int u=i[1],v=i[2],w=i[0];
		if(fin(u)!=fin(v)){
			tot++;
			fa[fin(u)]=fin(v);
			if(tot==n-1){
				cout<<w;
				return 0;
			}
		}
	}
	cout<<-1;
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...