P3101晚自习写题记录
P3101 [USACO14JAN]Ski Course Rating G - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
比较好的一道带权并查集题目
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
const int N = 510000;
int fa[N],h[510][510],s[510][510],id[505][510],tot[N],ts[N];//s[ ]表示起点,h[ ]表示海拔
struct node
{
ll w,x,y;
}a[N];
ll T,ans,ds,ce,m,n;//ds表示点的数量
int find(int x)
{
if(fa[x] != x)return fa[x] = find(fa[x]);
}
bool cmp(node a,node b)
{
return a.w < b.w;
}
int main()
{
cin>>m>>n>>T;
for(int i = 1;i <= m;i++)
for(int j = 1;j <= n;j++)
cin>>h[i][j];
for(int i = 1;i <= m;i++)
for(int j = 1;j <= n;j++)
cin>>s[i][j];
for(int i = 1;i <= m;i++)
for(int j = 1;j <= n;j++)
id[i][j] = ++ds,ts[ds] = s[i][j];//ts表示当前集合起点数量,每个点初始化为一个集合
for(int i = 1;i <= m;i++)
for(int j = 1;j <= n;j++)
{
//ce表示边的数量
//以下操作表示建边
if(i != m)ce++,a[ce].x = id[i][j],a[ce].y = id[i+1][j],a[ce].w = abs(h[i][j] - h[i+1][j]);
if(j != n)ce++,a[ce].x = id[i][j],a[ce].y = id[i][j+1],a[ce].w = abs(h[i][j] - h[i][j+1]);
}
for(int i = 1;i <= ds;i++)//所有边初始化
fa[i] = i,tot[i] = 1;//tot[]表示集合中的总点数
sort(a+1,a+ce+1,cmp);
for(int i = 1;i <= ce;i++)//枚举所有边
{
int fx = find(a[i].x);
int fy = find(a[i].y);
if(fx != fy)
{
fa[fx] = fy,ts[fy] += ts[fx],tot[fy] += tot[fx],ts[fx] = tot[fx] = 0;//最后的操作表示清空
if(tot[fy] >= T)ans += ts[fy] *a[i].w,ts[fy] = 0;
}
}
cout<<ans<<endl;
return 0;
}