题目:
点击打开链接
这个题目和前面的几个题目很相似,都是通过left-1 与 right压栈,进行连通性比较,说明了一个问题,就是并查集可以用来处理这种集合求解,或者相似性去重的操作。这个个题的难点在于,如何规定val值,在注释中解释了。
代码
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <map>
#define repf(i,from ,to) for(int i =from;i<=to;i++)
#define MAX 200005
using namespace std;
int val[MAX],pre[MAX],ans;
void init(int n){
repf(i,0,n)
{
pre[i]=i;
val[i]=0;
}
ans=0;
}
int Find(int a)
{
if(pre[a]!=a)
{
int temp = pre[a];
pre[a]=Find(pre[a]);
val[a]+=val[temp];
}
return pre[a];
}
void Merge(int a,int b,int si)
{
int fa = Find(a);
int fb = Find(b);
//这个地方我们可以画几个图,主要是计算祖先的节点信息,原因是,计算完祖先的位置信息后,就可以通过Find进行更新。
//比如 一条线是1 5 9 另一条线是2 4 8
//我们现在加进来了一个新的数据是5 8 ,那么怎么处理呢,我们需要让后面的数据的祖先变成前面的,为了统一。
//另一个就是更新这个val值,更新谁的呢,当然是2的,然后再次Find的时候就会把后面的数据val值全部更新。
if(fa>fb)
{
pre[fa]=fb;
val[fa]=val[b]-val[a]-si ;
}else if(fa<fb)
{
pre[fb] = fa;
val[fb] = val[a]-val[b]+si;
}
else if(val[b]-val[a]!=si)
{
ans++;
}
}
int n , m ;
int main(){
while(scanf("%d%d",&n,&m)!=EOF)
{
init(n);
repf(i,1,m)
{
int ai,bi,si;
scanf("%d%d%d",&ai,&bi,&si);
ai--;
Merge(ai,bi,si);
}
cout << ans <<endl;
}
}