题意
给出 n n n个点, m m m条无向边, q q q个询问.
每条边有权值 w w w, 每次询问删除所有权值小于 p p p的边后, 图中剩余的所有节点中, 能相互到达的节点对数.
思路
考虑用并查集。有两个问题:
1. 1. 1.并查集只能加边,不能减边。
2. 2. 2.数据的范围很大,如果我们每做一次判断都要进行一次遍历的话时间复杂度肯定会超时。
对于问题1:题目给的是破坏的多少条边,反过来经过排序之后逆向思维可以理解成查询的值变小了又加入了多少条边,这样我们就可以用并查集来进行处理了。
对于问题2:我们可以离散化 + + +离线询问,对查询的值由大到小排序(如果我们按照从小到大排序, 那么我们初始情况应认为 m m m条边都存在图中, 每次我们要删除小于 p i p_i pi的边. 由于并查集的删除操作并不好实现, 因此我们考虑从大到小排序)
最后思考 a n s ans ans:如果一个集合里面有 n n n个元素,那么就有 1 + 2 + 3 + … + n − 1 1+2+3+…+n-1 1+2+3+…+n−1个城市对。两个集合合并的话不能进行一个简单的相加,因为会有重复,意思是我们之前这两个集合各自的城市对已经加入 a n s ans ans了,合并之后又加一遍会有数据重复。所以我们可以先记录原先两个集合的节点数量 a , b a,b a,b,及合成后集合的节点的数量 s u m sum sum,新增加的节点对数就是 s u m × ( s u m − 1 ) / 2 − a × ( a − 1 ) / 2 − b × ( b − 1 ) / 2 sum\times (sum-1)/2 - a\times (a-1)/2 - b\times (b-1)/2 sum×(sum−1)/2−a×(a−1)/2−b×(b−1)/2。
#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
const int maxn = 2e5 + 100;
struct infor
{
int x, y;
int cost;
} e[maxn];
struct lian
{
long long sum;
int f;
} fa[maxn];
struct qs
{
long long v;
int id;
} se[maxn];
bool cmp1(infor x, infor y)
{
return x.cost > y.cost;
}
bool cmpc(qs x, qs y)
{
return x.v > y.v;
}
int find(int x)
{
if (x == fa[x].f)
return x;
fa[x].f = find(fa[x].f);
return fa[x].f;
}
void solve()
{
long long cnt[maxn];
int n, m, q,i,j=0;
scanf("%d%d%d", &n, &m, &q);
for (i = 1; i <= n; i++)
{
fa[i].sum = 1;
fa[i].f = i;
}
for (i = 0; i < m; i++)
scanf("%d%d%d", &e[i].x, &e[i].y, &e[i].cost);
for (i = 0; i < q; i++)
{
scanf("%lld", &se[i].v);
se[i].id = i;
}
sort(e, e + m, cmp1);
sort(se, se + q, cmpc);
long long ans = 0;
for (i = 0; i < q; i++)
{
for (j; j < m; j++)
{
int from = e[j].x;
int to = e[j].y;
int c = e[j].cost;
if (c < se[i].v)
break;
from = find(from);
to = find(to);
if (from != to)
{
long long a, b;
a = fa[from].sum;
b = fa[to].sum;
fa[from].f = to;
fa[to].sum += a;
ans += fa[to].sum * (fa[to].sum - 1) / 2 - a * (a - 1) / 2 - b * (b - 1) / 2;
}
}
cnt[se[i].id] = ans;
}
for (i = 0; i < q; i++)
printf("%lld\n", cnt[i]);
}
int main()
{
int t;
cin >> t;
while (t--)
{
solve();
}
return 0;
}