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;
        
  }
}
复制代码

 

posted @   liyishui  阅读(28)  评论(0编辑  收藏  举报
编辑推荐:
· 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)
点击右上角即可分享
微信分享提示