思路:种类并查集的每个节点应该保存它的父节点以及他和父节点之间的关系。假设root表示根结点,sum[i-1]表示i到根结点的和,那么sum[j-1] - sum[i]可以得到区间[j, i]的和。那么给定(x, y, real)可以看作x-1到节点y的和为real
AC代码
#include <cstdio> #include <cmath> #include <cctype> #include <algorithm> #include <cstring> #include <utility> #include <string> #include <iostream> #include <map> #include <set> #include <vector> #include <queue> #include <stack> using namespace std; #pragma comment(linker, "/STACK:1024000000,1024000000") #define eps 1e-10 #define inf 0x3f3f3f3f #define PI pair<int, int> typedef long long LL; const int maxn = 200000 + 5; struct node{ int par; int real; }a[maxn]; int find(int x, int &root) { if(a[x].par == x) { root = x; return a[x].real; } int r = a[x].real + find(a[x].par, root); //路径压缩 a[x].par = root; return a[x].real = r; } bool unionset(int x, int y, int real) { int r1, r2; int rx = find(x, r1), ry = find(y, r2); if(r1 == r2) { if(rx - ry != real) return false; } else { //合并 a[r1].par = y; a[r1].real = real - rx; } return true; } int main() { int n, m; while(scanf("%d%d", &n, &m) == 2) { for(int i = 0; i <= n; ++i) { a[i].par = i; a[i].real = 0; } int x, y, r, ans = 0; for(int i = 0; i < m; ++i) { scanf("%d%d%d", &x, &y, &r); if(!unionset(x-1, y, r)) ans++; } printf("%d\n", ans); } return 0; }
如有不当那个之处欢迎指出!