卧薪尝胆,厚积薄发。
HNOI2005 狡猾的商人
Date: Fri Sep 07 10:11:08 CST 2018 In Category: NoCategory

Description:

给出序列 $[l,r]$ 的和,判断是否合法。
$1\le n \le 100,1\le T \le 100$

Solution:

转成前缀和相减,用带权并查集维护,并查集维护的是从这个点到并查集的根的和,路径压缩时可以一并维护。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cctype>
#include<cstring>
using namespace std;
inline int read()
{
register int res = 0,f = 1;
register char c = getchar();
while(!isdigit(c))
{
if(c == '-')f = -1;
c = getchar();
}
while(isdigit(c))
{
res = (res << 1) + (res << 3) + c - '0';
c = getchar();
}
return res * f;
}
#define MAXN 110
int n,m;
int f[MAXN],g[MAXN];
int get(int x){return f[x] == -1 ? 0 : g[x] + get(f[x]);}
int find(int x)
{
if(f[x] == -1)return x;
int p = get(f[x]);
g[x] = g[x] + p;f[x] = find(f[x]);
return f[x];
}
bool tag;
void merge(int a,int b,int c)
{
int p = find(a),q = find(b);
if(p != q)
{
f[q] = p;
g[q] = c + get(a) - get(b);
}
else
{
if(get(b) - get(a) != c)
{
tag = false;
}
}
return;
}
void work()
{
scanf("%d%d",&n,&m);
memset(f,-1,sizeof(f));
memset(g,0,sizeof(g));
int a,b,c;
tag = true;
for(register int i = 1;i <= m;++i)
{
a = read();b = read();c = read();
merge(a - 1,b,c);
}
if(tag)puts("true");
else puts("false");
return;
}
int main()
{
int testcases;
scanf("%d",&testcases);
while(testcases--)work();
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡