[题解]逃离地球

题意简述

有一个星系,共有\(n*m\)个星球,排成\(n\)\(m\)列。

初始星球之间没有道路。接下来给定\(P\)种魔法\(1\)\(Q\)种魔法\(2\)

  • 魔法\(1\):第\(i\)种魔法用\(a_i,b_i,c_i\)描述。表示你可以任选星系的一行,在第\(a_i\)和第\(b_i\)个星球之间建立一条航道,消耗\(c_i\)的能量。
  • 魔法\(2\):第\(i\)种魔法用\(x_i,y_i,z_i\)描述。表示你可以任选星系的一列,在第\(x_i\)和第\(y_i\)个星球之间建立一条航道,小号\(z_i\)的能量。

询问要想让所有星球互相连通,最少需要消耗多少太阳能。

输入格式:一行\(n,m,p,q\),接下来是\(p+q\)行,每行\(3\)个数用于描述魔法\(1,2\)的信息。

样例:

Sample #1

Input

2 2 1 2  
1 2 1  
2 1 1  
2 1 1

Output

3
Sample #2

Input

2 3 4 1  
2 3 5  
3 2 7  
1 2 6  
1 1 8  
2 1 5

Output

26

数据范围:\(1\le n,m,P,Q\le 10^5\)\(1≤c_i,z_i≤10^8\)

思路简述

根据贪心的思想,我们如果找到一种魔法消耗很小,那我们会想到对所有行/列都使用这种一次魔法。

于是想到使用最小生成树来解决。把行标和列标看作节点,魔法看作边,魔法消耗看作边权。那么就相当于对这样一个拥有\(2\)棵树的森林跑一次最小生成树。需要注意的是,不能先跑行再跑列,而是需要一同排序,一并处理。原因就是行数和列数是在变化的(比如我们已经对所有列都使用了魔法,连接了\(1,2\)行,那么我们可以理解为我们删掉了\(1\)行。因为只要能连接到第\(2\)行的一定也能连接到第\(1\)行。所以我们再对行使用魔法的时候就可以少考虑一行,即这一组魔法总消耗应该等于 单次消耗\(\times(\)当前行数\(-1)\))。

正确性证明:
设有两边权值分别是\(u,v\),而\(u>v\)。那么

  • 显然\(u,v\)同为魔法\(1\)或同为魔法\(2\)时先用\(v\)最优。

  • 如果\(u,v\)一个是魔法\(1\),一个是魔法\(2\),则先用\(u\)和先用\(v\)的花费如下:

    • 先用\(u\)\(u*n+v*(m-1)=u*n+v*m-v\)
    • 先用\(v\)\(v*m+u*(n-1)=u*n+v*m-u\)

    故还是先用\(v\)更优。

代码使用Kruskal实现,需要用并查集。为了行标和列标不冲突所以行标节点统一\(+m\)存储,因此注意空间需要开\(2\)倍。

#include<bits/stdc++.h>
#define N 100010
#define M 100010
#define int long long
using namespace std;
struct edge{
	int u,v,w;
}edges[2*M];//开两倍是因为行列都要存
bool cmp(edge a,edge b){return a.w<b.w;} 
int n,m,p,q,fa[2*N],ans;
int find(int x){
	if(fa[x]==x) return x;
	else return fa[x]=find(fa[x]);
}
signed main(){
	cin>>n>>m>>p>>q;
	for(int i=1;i<=n+m;i++) fa[i]=i;
	for(int i=1;i<=p;i++){//选行连列 
		cin>>edges[i].u>>edges[i].v>>edges[i].w;
	}
	for(int i=p+1;i<=p+q;i++){//选列连行 
		cin>>edges[i].u>>edges[i].v>>edges[i].w;
		edges[i].u+=m,edges[i].v+=m;
	}
	sort(edges+1,edges+1+p+q,cmp);
	int nn=n,mm=m;
	for(int i=1,cnt=0;i<=p+q;i++){
		int u=find(edges[i].u),v=find(edges[i].v);
		if(u==v) continue;
		cnt++;
		fa[u]=v;
		if(u<=m) ans+=nn*edges[i].w,mm--;//列节点
		else ans+=mm*edges[i].w,nn--;//行节点 
		if(cnt==n+m-2) break;
	}
	cout<<ans;
	return 0;
}
posted @ 2024-07-05 09:15  Sinktank  阅读(25)  评论(0编辑  收藏  举报
★CLICK FOR MORE INFO★ TOP-BOTTOM-THEME
Enable/Disable Transition
Copyright © 2023 ~ 2024 Sinktank - 1328312655@qq.com
Illustration from 稲葉曇『リレイアウター/Relayouter/中继输出者』,by ぬくぬくにぎりめし.