加权并查集
由于给出信息的是一些一个区间的和为多少,我们显然并不好处理出每一个点应该为多少,这我们根本做不到
但是我们想一下,如果要求一个区间([l,r])的和,那么我们是不是可以利用前缀和(p[r]-p[l-1])得到
所以一组信息(l,r,k)其实可以利用前缀和写成(p[r]-p[l-1]=k)的形式
于是我们可以考虑将这些这前缀和的信息利用并查集来合并,同时我们还要存储一个(s[i])表示(p[fa[i]]-p[i])为多少,即根节点与每个点的差为多少
如果对于一条信息(l,r,k),(l-1,r)已经有了关系,即(l-1)和(r)在一个并查集里,我们就看一看(p[r]-p[l-1])即(p[root]-p[l-1]-(p[root]-p[r])=s[x-1]-s[y])是否等于(k)就好了
如果(l-1)与(r)没有关系,那么就将这两个并查集合并一下,这里也要推一下式子(刚上来这里的式子推错了,真尴尬)
之后就是一个加权并查集的板子了
#include<iostream>
#include<cstring>
#include<cstdio>
#define re register
#define maxn 101
int fa[maxn],s[maxn];
inline int read()
{
char c=getchar();
int x=0,r=1;
while(c<'0'||c>'9'){if(c=='-') r=-1;c=getchar();}
while(c>='0'&&c<='9')
x=(x<<3)+(x<<1)+c-48,c=getchar();
return x*r;
}
int find(int x)
{
if(fa[x]==x) return x;
int an=find(fa[x]);
s[x]+=s[fa[x]];
return fa[x]=an;
}
int n,m,T;
int main()
{
T=read();
while(T--)
{
n=read();
m=read();
for(re int i=0;i<=n;i++) fa[i]=i,s[i]=0;
int opt=1;
int x,y,z;
for(re int i=1;i<=m;i++)
{
x=read();
y=read();
z=read();
int xx=find(x-1);
int yy=find(y);
if(xx==yy)
{
if(s[x-1]-s[y]!=z) opt=0;
}
else
{
if(!opt) break;
fa[xx]=yy;
s[xx]=-s[x-1]+s[y]+z;
}
if(!opt) break;
}
if(!opt) puts("false");
else puts("true");
}
return 0;
}