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; } }
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号