hdu3038带权并查集
郁闷得很,送出了好几发wa,找不到错在哪
--------
来自两天后的更新:
我知道错在这里了:
if(fa[x]!=x) { fa[x]=find(fa[x]); val[x]+=val[fa[x]]; }
在进行这么多次回溯后,你爸爸已经不是你爸爸了
而我们记录是是对于父节点的相对关系。
所以要用一个tmp存一下。
---------
学到:并查集的应用
这道题出现矛盾当且仅当读入的区间的两个端点均已出现过,且这两个端点有一个共同的端点。
当两个区间父亲相同时我们尝试计算。
当不同时我们可以合并。
合并的原理是,类似于把其中一个端点作为参照,val就是这个并查集中的点到这个参照点的差。
又因为差值和点是一一对应的,所以也不必担心什么加了后会出现负数啦,负数就是在它左边。
然后在合并的时候只合并f1的val是因为这个并查集如果下次有再用到的话,在find函数里会更新,没有那就没有这种需求了。
以及,为什么是l--?
看了很多博客,有的说这样才可以合并【1,5】【6,10】区间,有的说端点会重复计算
我的理解是:
假设我们已经知道1-100以及1-60,那么61-100我们就能计算了
此时题目给出61-100
把61变成60,60,100,就都在同一个并查集里,并且算出来结果是对的。
如果不加的话,61就不在并查集里了。
#include <iostream> #include <math.h> #include <string.h> #include <vector> #include <map> #include <queue> #include <stdio.h> #include <algorithm> #include <cstdio> using namespace std; int ans,n,m,val[500000],fa[500000]; int find(int x) { if(fa[x]!=x) { fa[x]=find(fa[x]); val[x]+=val[fa[x]]; } return fa[x]; } void pre( ) { ans=0; for(int i=0;i<=n;i++) { fa[i]=i; val[i]=0; } } void unit(int a,int b,int value) { int f1=find(a),f2=find(b); if(f1==f2)//同一个父亲可以判断区间长度了 { if(abs(val[b]-val[a])!=value) { ans++; } } else { fa[f2]=f1; val[f2]=val[a]+value-val[b]; } } int main() { //freopen("9241.in","r",stdin); while(~scanf("%d%d",&n,&m)) { pre( ); for(int i=1;i<=m;i++) { int l,r,e; scanf("%d%d%d",&l,&r,&e); l--; unit(l,r,e); } cout<<ans<<endl; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)