題意:給定n個城市,求最小的權值使得所有城市都有電,對於每個城市要麼建電站,要麼連接到已經有電的城市,ij兩點連接邊權爲(abs(arr[i].x - arr[j].x) + abs(arr[i].y - arr[j].y) ) * (arr[i].k + arr[j].k),建電站權值爲arr[i].c
解題思路:轉換問題,把建電站也變爲權值邊,建電站代表連接虛點0的邊,然後跑最小生成樹即可。
對於答案,若拋開虛點後可能是一片森林,對每個森林跑生成樹不好操作,而建虛點後權值統一操作統一
正確性:建虛點後跑最小生成樹必然有至少一個電站,因爲要將0點連接到樹中,符合題意
最優,按邊權排序後若出現了虛點邊則表示在當前點建電站比權值更大的連接更優,最後按邊類型統計即可
/*
Zeolim - An AC a day keeps the bug away
*/
//#pragma GCC optimize(2)
//#pragma GCC ("-W1,--stack=128000000")
#include <bits/stdc++.h>
using namespace std;
#define mp(x, y) make_pair(x, y)
#define fr(x, y, z) for(int x = y; x < z; ++x)
#define pb(x) push_back(x)
#define mem(x, y) memset(x, y, sizeof(x))
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef std::pair <int, int> pii;
typedef std::vector <int> vi;
//typedef __int128 ill;
const ld PI = acos(-1.0);
const ld E = exp(1.0);
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll MOD = 1e9 + 7;
const ull P = 13331;
const int MAXN = 4e6 + 100;
int n;
struct pit
{
ll x, y;
ll k, c;
}arr[MAXN];
struct node
{
ll x, y, val;
bool operator < (const node b) const
{
return val < b.val;
}
}edge[MAXN];
int p = 0;
int fa[MAXN] = {0};
int findfa(int x)
{
return x == fa[x] ? x : fa[x] = findfa(fa[x]);
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
//freopen("d:\out.txt","w",stdout);
//freopen("d:\in.txt","r",stdin);
cin >> n;
for(int i = 0; i < n + 10; ++i) fa[i] = i;
for(int i = 1; i <= n; ++i)
cin >> arr[i].x >> arr[i].y;
for(int i = 1; i <= n; ++i)
cin >> arr[i].c;
for(int i = 1; i <= n; ++i)
cin >> arr[i].k;
for(int i = 1; i <= n; ++i)
{
for(int j = i + 1; j <= n; ++j)
{
edge[p++] = node{i, j, (abs(arr[i].x - arr[j].x) + abs(arr[i].y - arr[j].y) ) * (arr[i].k + arr[j].k)};
}
}
for(int i = 1; i <= n; ++i)
{
edge[p++] = node{i, 0, arr[i].c};
}
sort(edge, edge + p);
ll ans = 0;
vector <int> bu;
vector <pii> ad;
for(int i = 0; i < p; ++i)
{
int p = findfa( edge[i].x ), q = findfa( edge[i].y );
if(p != q)
{
fa[p] = q;
ans += edge[i].val;
if(edge[i].y == 0)
{
bu.pb(edge[i].x);
}
else
{
ad.pb(mp(edge[i].x, edge[i].y) );
}
}
}
cout << ans << '\n';
cout << bu.size() << '\n';
for(auto x : bu)
{
cout << x << ' ';
}
cout << '\n';
cout << ad.size() << '\n';
for(auto x : ad)
{
cout << x.first << ' ' << x.second << '\n';
}
return 0;
}
/*
13 8
100 90 80 70 60 50 40 30
0
0
0
0
1
1
2
2
3
7
7
8
8
*/
/*
5 3
5 4 3
0
0
1
1
*/