知识点:离线,并查集
难度:5
这个运用的知识点是离线思想+并查集,怎么想到的,只要考虑出暴力的算法就很容易想到了,首先,我们点开洛谷右边相关讨论最上面的一个翻译,简洁的叙述了这个题目的意思,这样就不用自己看题了,定义两个点的熟练度是这两个点的路径上最小的边权,然后是给出询问,问到某点熟练度不小于某值的点的个数
我们考虑暴力的做法,每次询问,先初始化,每个点都自成一个连通块,然后按照题意,求到给定点熟练度不小于某值的点的个数,很自然的想到,这就等价于,我们把大于等于给定边权的边连接上,然后看要查询的点所在连通块的点的个数减一,就是这个询问我们要求的值,这很明显是正确的,因为当前查询点到其它连通块,肯定是要经过一条边权小于给定值的边的,那么那些连通块的点其实就不是答案,因为熟练度的定义是经过路径最小值,
想出来了暴力的做法,离线方法就很好想了,暴力的做法就是加边,离线就是我们记录输入的顺序,把所有的边按照大小顺序排序,把所有查询按照查询边权的大小排序,这样我们外层循环是按照边权大小处理查询,然后内层一个循环把大于等于当前查询边权的边加上,这样并不影响后面的查询,因为后面的查询边权是小于等于当前的,我们查到后面的时候,现在这些边权比较大的边肯定也是要连上的,最后按照顺序输出就行了,
这样除了并查集的操作这个题就变成1e5的线性的离线做法了,这个题自己没看题解10分钟估计就写出来了,还是很高兴的,但是这是并查集的练习题,提前知道这个是用并查集做的,至于离线的思想是链表的时候练过,这里才能想起来,发现并查集和离线思想的练习也不少
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
struct node {
int x, y, z;
} a[N], b[N];
int fa[N], d[N], ans[N];
int get(int x) {
if (x == fa[x]) return x;
return fa[x] = get(fa[x]);
}
void merge(int x, int y) {
int fx = get(x), fy = get(y);
fa[fx] = fy;
d[fy] += d[fx];
}
bool cmp1(node a, node b) {
return a.z > b.z;
}
bool cmp2(node a, node b) {
return a.x > b.x;
}
int main() {
for (int i = 0; i < N; i++) {
fa[i] = i;
d[i] = 1;
}
int n, q;
cin >> n >> q;
for (int i = 1; i <= n - 1; i++) {
cin >> a[i].x >> a[i].y >> a[i].z;
}
for (int i = 1; i <= q; i++) {
cin >> b[i].x >> b[i].y;
b[i].z = i;
}
sort(a + 1, a + n, cmp1);
sort(b + 1, b + q + 1, cmp2);
int ind = 1;
for (int i = 1; i <= q; i++) {
while (ind <= n - 1 && a[ind].z >= b[i].x) {
merge(a[ind].x, a[ind].y);
ind++;
}
ans[b[i].z] = d[get(b[i].y)] - 1;
}
for (int i = 1; i <= q; i++) cout << ans[i] << '\n';
return 0;
}
本文介绍了一种结合离线思想与并查集的数据结构算法应用案例。通过将暴力算法离线化,实现高效的边权处理及点熟练度查询,解决了特定路径最小边权的问题。

被折叠的 条评论
为什么被折叠?



