3.1并查集
算法理解
维护两个点是否能到达,于是将互相能到达的点用其中一个点来代表4
T1:
板子
T2:
带权并查集简化,用dis来代表一个点到其中并查集中的头的距离,注意dis最开始应赋值为0,因为考虑当这个点直接与代表元素相连时,如果重复find该元素,dis[fa]会被加很多次,只有当其为0时才能解决问题
T3:
带权并查集!
我们将操作的x,y放到一个并查集内,相等权值为0,不相等权值为1
注意考虑下边的图,用x到find(x)和y到find(y)来更新find(x)和find(y)
T4:
考虑贪心,我们将物品价值从大到小排序,然后对于一个物品销售出去日期越大更优,用并查集维护第一个能卖出去的日子
傻逼题目,如果你TLE了,请删掉EOF,改成cin
T5:
将删边变为加边,先从边权最大的开始加,如果边两边都有特殊点,则不加
傻逼傻逼傻逼傻逼傻逼题目,如果你奇奇怪怪的30分了,建议你去洛谷交一下,如果洛谷也过了,那么建议你递一份代码上去,因为调它没有意义(本人的傻逼言论,保留以供后世嘲笑)
2024.10.31更新:感谢crk学长,帮我找出来了错误,并不是题目的问题,是本人傻逼了
应该先排除两个点本身就在一个连通块的情况
粘出来代码以供嘲笑
点击查看傻逼代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5,M=5e5+5;
int n,k,m,a,b,c,d,ans;
int fa[N],v[N];
struct edge{
int a,b,c;
}e[M];
bool cmp(edge x,edge y){
return x.c>y.c;
}
int find(int x){
if(x==fa[x]) return x;
return fa[x]=find(fa[x]);
}
void merge(int x,int y){
int xx=find(x),yy=find(y);
if(xx==yy) return;
fa[xx]=yy;
v[yy]=v[xx]||v[yy];
}
signed main(){
scanf("%lld%lld%lld",&n,&m,&k);
for(int i=1;i<=k;i++){
scanf("%lld",&d);
v[d+1]=1;
}
for(int i=1;i<=m;i++){
scanf("%lld%lld%lld",&a,&b,&c);
e[i]={a+1,b+1,c};
}
sort(1+e,e+1+m,cmp);
for(int i=0;i<=n;i++){
fa[i]=i;
}
for(int i=1;i<=m;i++){
int xxx=find(e[i].a),yyy=find(e[i].b);
if(v[xxx]&&v[yyy]&&xxx!=yyy) ans+=e[i].c;//一定要加xxx!=yyy,要不然就是我说的以上情况
else merge(xxx,yyy);
}
printf("%lld",ans);
}
2024.11.14更新:
此题题解有误,考虑一组hack
6 7 2
2 4
1 5 6
1 2 7
2 5 7
2 3 8
3 4 7
3 6 7
4 6 6
正常贪心的话会得出13,但其实答案是8
原因是洛谷上的原题是一棵树,而此题是一张图,树保证了两个点路径唯一,所以只要断掉路径上最小的权值即可
T6:
道路排好序,询问离线排序查询,然后注意不要和我一样手残把j打成i调一上午
T7:
我将所有相等的条件先做,不相等条件后做,只要判断是否合法即可
T8:
因为只有将黑色染成白色操作,所以只需要维护一个并查集统计一段连续的区间内下一个黑格子在哪里,注意当j==n时fa[n+1]为0,所以注意特判,或直接设为n+1也可
T9:
一次查询可以用前缀和表示,所以可以用带权并查集维护然后判断合法即可
T10:
先对每一行开一个并查集,维护每一个点之后第一个海的位置在哪里,再维护一个包含所有点的并查集,维护连通性
对于一次海洋变陆地,我们查找到海的位置,然后将其上下左右在判断连通性的并查集中加入即可