只有一个地方需要注意:
设节点a的根为u,b的跟为v,则:a = u + d[a]; b = v + d[b];
已知:b-a=w。所以v - u = d[a] - d[b] + w;
在合并两个集合修改根节点时,把v的根改为u,同时v到根的距离为d[a] - d[b] + w;
1 #include <cstdio> 2 #include <cstring> 3 4 const int MAXN = 100010; 5 6 int pa[MAXN]; 7 long long int d[MAXN]; 8 9 int findset( int x ) 10 { 11 if ( pa[x] == x ) return x; 12 int root = findset( pa[x] ); 13 d[x] += d[ pa[x] ]; 14 return pa[x] = root; 15 } 16 17 int main() 18 { 19 int N, M; 20 while ( scanf( "%d%d", &N, &M ), N || M ) 21 { 22 for ( int i = 0; i <= N; ++i ) 23 { 24 pa[i] = i; 25 d[i] = 0; 26 } 27 while ( M-- ) 28 { 29 char op[4]; 30 scanf( "%s", op ); 31 int a, b, w; 32 if ( op[0] == '!' ) 33 { 34 scanf( "%d%d%d", &a, &b, &w ); 35 int u = findset(a); 36 int v = findset(b); 37 pa[v] = u; 38 d[v] = d[a] - d[b] + w; 39 } 40 else 41 { 42 scanf( "%d%d", &a, &b ); 43 int u = findset(a); 44 int v = findset(b); 45 if ( u != v ) puts("UNKNOWN"); 46 else printf( "%lld ", d[b] - d[a] ); 47 } 48 } 49 } 50 return 0; 51 }