小白月赛54 F.Traveling(图论&构造)
显然
考虑 的
,可以构造
接下来只需考虑 的集合
。
我们可以选择最小的 然后连
然后集合中的其他点连
。
注意特判和构造的边数小于
和大于
的情况。
不足 可以构造无效边
超过无解。
#include <bits/stdc++.h>
using namespace std;
const int N = 3E5 + 100, inf = 1E9;
int n, m;
int arr[N];
set<int> vis[N];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m;
int Min = numeric_limits<int>::max();
for (int i = 1; i <= n; i++) {
cin >> arr[i];
Min = min(Min, arr[i]);
}
if (m > 1LL * n * (n - 1) / 2 || arr[1] > Min || arr[n] > Min) {
cout << "No" << "\n";
return 0;
}
vector<array<int, 3> > e;
vector<array<int, 2> > v;
e.push_back({1, n, Min});
vis[1].insert(n);
for (int i = 2; i < n; i++) {
int d = arr[i] - arr[1];
if (d & 1) {
if (arr[1] == 0) {
cout << "No" << "\n";
return 0;
}
v.push_back({arr[i], i});
} else {
e.push_back({1, i, d / 2});
vis[1].insert(i);
}
}
sort(v.begin(), v.end());
if (!v.empty()) {
auto [d1, x] = v.front();
auto d0 = arr[1];
e.push_back({1, x, d1-d0});
vis[1].insert(x);
e.push_back({x, n, d0});
vis[x].insert(n);
for (int i = 1; i < v.size(); i++) {
auto [d2, y] = v[i];
if (x < y) {
e.push_back({x, y, (d2 - d1) / 2});
vis[x].insert(y);
} else {
e.push_back({y, x, (d2 - d1) / 2});
vis[y].insert(x);
}
}
}
if (m < e.size()) {
cout << "No" << "\n";
return 0;
}
for (int i = 1; i <= n && e.size() < m; i++) {
for (int j = i + 1; j <= n && e.size() < m; j++) {
if (vis[i].find(j) == vis[i].end()) {
e.push_back({i, j, inf});
vis[i].insert(j);
}
}
}
cout << "Yes" << "\n";
for (auto [u, v, w] : e) {
cout << u << " " << v << " " << w << "\n";
}
return 0;
}