LA 6187 - Never Wait for Weights 并查集的带权路径压缩

只有一个地方需要注意:

设节点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\n", d[b] - d[a] );

47             }

48         }

49     }

50     return 0;

51 }

 

你可能感兴趣的:(wait)