k-City
题意:
n个点m条边,有q次询问每次给当一个p,当两个点之间的边权小于p时,这条边就会被摧毁掉,问每次给定p的时候有多少对点相互连通;
思路:
每次查询,都要遍历一遍所有的点,判断这条边是否大于p,时间复杂度远不够,假设p1<p2,当一条边大于p2的时候一定大于p1,所以可以由大到小做,这样省掉了许多判断的时间,维护连通块的节点个数可以直接使用并查集
题解:
#include <bits/stdc++.h>
#define x first
#define y second
#define IOS ios::sync_with_stdio(false);cin.tie(0);
#define lowbit(x) x&(-x)
#define INF 0x7fffffff
#define eb emplace_back
#define divUp(a,b) (a+b-1)/b
#define mkp(x,y) make_pair(x,y)
#define lb lower_bound
#define ub upper_bound
#define int long long
using namespace std;
typedef unsigned long long ull;
typedef pair<int, int> pii;
int gcd(int a, int b) {return b == 0 ? a : gcd(b, a % b);};
bool checkP2(int n) {return n > 0 and (n & (n - 1)) == 0;};
const int N = 2000010;
struct edge {
int u, v, w;
bool operator <(const edge& t) const {
return w > t.w;
}
} E[N];
struct query {
int power, id;
bool operator <(const query& t) const {
return power > t.power;
}
} Q[N];
int s[N], p[N], ans[N];
int find(int x) {
if (x != p[x]) p[x] = find(p[x]);
return p[x];
}
void solve() {
int n, m, q;
cin >> n >> m >> q;
int u, v, w;
for (int i = 1; i <= n; i++) p[i] = i, s[i] = 1;
for (int i = 1; i <= m; i++) {
cin >> u >> v >> w;
E[i] = {u, v, w};
}
for (int i = 1; i <= q; i++) {
cin >> w;
Q[i] = {w, i};
ans[i] = 0;
}
sort(E + 1, E + 1 + m);
sort(Q + 1, Q + 1 + q);
int cur = 1;
int sum = 0;
for (int i = 1; i <= q; i++) {
while (E[cur].w >= Q[i].power and cur <= m) {
if (cur > m) break;
int u=E[cur].u,v=E[cur].v;
int pa = find(u);
int pb = find(v);
if (pa != pb) {
sum += s[pa] * s[pb];
p[pa] = pb;
s[pb] += s[pa];
}
cur++;
}
ans[Q[i].id] = sum;
}
for (int i = 1; i <= q; i++) cout << ans[i] << endl;
}
signed main() {
IOS;
int _; while (cin >> _) {while (_--)solve();}
return 0;
}