题目大意:
有
个点,
条边,我们称边权为键
一个点和另一个点处于同一集合,当且仅当两个点之间存在直接或间接的键组成的路径
一个人对一个有n个点的集合好感度为k[i],当好感度总和大于K时这是个合理方案
另一个人要断裂某些键,问保留的键的频宽(必须只有x~y开放)为多少时可以满足以上条件
如果没有输出T_T
对于100% 的数据 频率 。
Sample Input
输入1:
4 4 52
1 50 2 9
1 2 6
2 3 8
3 4 4
1 4 3
输入2:
4 4 10
1 5 2 9
1 2 6
2 3 8
3 4 4
1 4 3
输入3:
4 4 10
1 4 2 9
1 2 6
2 3 8
3 4 4
1 4 3
Sample Output
输出1:
0
样例解释1:频段3Hz ~ 3Hz 或 4Hz ~ 4Hz 或 6Hz ~ 6Hz 或 8Hz ~ 8Hz
输出2:
2
样例解释2:频段4Hz ~ 6Hz
输出3:
T_T
解题思路:
首先将
条边按照键从小到大排序
然后我们枚举左端点,用
储存
个只有一个点的集合的好感度和,枚举右端点(从小到大加入键)
如果加入这一段键可以使得
的话(并查集维护) 更新答案
因为左端点固定,右端点从左端点处开始枚举,所以枚举到的第一个满足条件的答案就是对于这个左端点的最佳答案
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int inf = 1e9;
struct FOX {
int x, y, key;
}a[5050];
int n, m, K, ans, sum;
int k[1050], fa[1050], size[1050];
bool cmp(FOX X, FOX Y) { return X.key < Y.key; }
int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
int main() {
scanf("%d %d %d", &n, &m, &K);
for (int i = 1; i <= n; ++i)
scanf("%d", &k[i]);
for (int i = 1; i <= m; ++i)
scanf("%d %d %d", &a[i].x, &a[i].y, &a[i].key);
ans = inf; //初始化
sort(a+1, a+m+1, cmp); //排序
for (int left = 1; left <= m; ++left) {
if (a[left].key == a[left-1].key) continue;
//如果当前边的键与上次的相同,那么没必要再找一次,因为答案是一样的,
//但是下面只会用到左端点往右的,所以前面的不会被统计到,所以不加可能会错
sum = k[1] * n; //算出单身点的好感度
for (int i = 1; i <= n; ++i)
fa[i] = i, size[i] = 1; //初始化
for (int right = left; right <= m; ++right) {
if (a[right].key - a[left].key > ans) break; //如果频宽已经比答案要大了那就不是最小的了可以直接退出
int x1 = find(a[right].x), y1 = find(a[right].y);
if (x1 == y1) continue;
sum += k[size[x1] + size[y1]] - (k[size[x1]] + k[size[y1]]); //更新好感度
size[x1] += size[y1]; fa[y1] = x1;
if (sum >= K) { ans = a[right].key - a[left].key; break; } //更新答案
}
}
if (ans == inf) puts("T_T");
else printf("%d\n", ans);
}