UESTC 1832

今天比赛的时候做的一个题目。感觉这个题目不错。

题目描述:

Description

In a laboratory, an assistant, Nathan Wada, is measuring weight differences between sample pieces pair by pair. He is using a balance because it can more precisely measure the weight difference between two samples than a spring scale when the samples have nearly the same weight.
He is occasionally asked the weight differences between pairs of samples. He can or cannot answer based on measurement results already obtained.
Since he is accumulating a massive amount of measurement data, it is now not easy for him to promptly tell the weight differences. Nathan asks you to develop a program that records measurement results and automatically tells the weight differences.

Input

The input consists of multiple datasets. The first line of a dataset contains two integers N and M. N denotes the number of sample pieces (2 <= N <= 100, 000). Each sample is assigned a unique number from 1 to N as an identifier. The rest of the dataset consists of M lines (1 <= M <= 100, 000), each of which corresponds to either a measurement result or an inquiry. They are given in chronological order.
A measurement result has the format,

! a b w

which represents the sample piece numbered b is heavier than one numbered a by w micrograms (a != b). That is, w = wb - wa, where wa and wb are the weights of a and b, respectively. Here, w is a non-negative integer not exceeding 1,000,000.
You may assume that all measurements are exact and consistent.
An inquiry has the format,

? a b

which asks the weight difference between the sample pieces numbered a and b (a != b).
The last dataset is followed by a line consisting of two zeros separated by a space.

Output

For each inquiry, ? a b, print the weight difference in micrograms between the sample pieces numbered a and b, wb - wa, followed by a newline if the weight difference can be computed based on the measurement results prior to the inquiry. The difference can be zero, or negative as well as positive. You can assume that its absolute value is at most 1,000,000. If the difference cannot be computed based on the measurement results prior to the inquiry, print `UNKNOWN' followed by a newline.

Sample Input

2 2
! 1 2 1
? 1 2
2 2
! 1 2 1
? 2 1
4 7
! 1 2 100
? 2 3
! 2 3 100
? 2 3
? 1 3
! 4 3 150
? 4 1
0 0

Sample Output

1
-1
UNKNOWN
100
200
-50

题目的意思是给你n对关系和查询。关系告诉你的是A比B小C,询问的是A比B小多少?

刚看这个题目觉得是个暴力,而且时限开那么宽可以裸过。

后来发现根本不是这么一回事呢。

想了一会儿后就果断的发现这个题目的解法是并查集,对没错就是并查集。

这个题目是带权值的并查集。对于每个节点,除了保存它的父亲节点以外还要保存它与父亲节点的差,这样就能实现同一个集合中任意两个元素的大小比较了。

同时发现,由于对于同一个集合中的每一个元素都是和它的父亲节点做比较,所以整个来说这一个集合是一棵树,所有的集合可以看成是一个森林。

其实题目并不难,思路清楚很容易就写出来了。

可惜我写的时候写挫了一个小地方,wa了若干发,T_T

我的代码,仅供参考,据说效率还不错。

#include <cstdio>
#define maxn 100100
using namespace std;

int f[maxn],a[maxn],n,m;
char ch[5];

int father(int x)
{
    int ff=f[x];
    if (f[x]==x) return x;
    f[x]=father(f[x]);
    a[x]+=a[ff];
    return f[x];
}

int main()
{
    int A,B,C,f1,f2;
    while (scanf("%d%d",&n,&m) && (n+m))
    {
        for (int i=1; i<=n; i++) f[i]=i,a[i]=0;
        while (m--)
        {
            scanf("%s",ch);
            if (ch[0]=='!')
            { 
                scanf("%d%d%d",&B,&A,&C);
                f1=father(A);
                f2=father(B);
                if (f1==f2) continue;
                f[f1]=f2;
                a[f1]=C+a[B]-a[A];
            }
            else if (ch[0]=='?')
            {
                scanf("%d%d",&A,&B);
                f1=father(A);
                f2=father(B);
                if (f1!=f2) puts("UNKNOWN");
                else printf("%d
",a[B]-a[A]);
            }
        }
    }
    return 0;
}

题目不难,好好理解这个father中的带权值的路径压缩。

如有转载,请注明出处(http://www.cnblogs.com/lochan)
原文地址:https://www.cnblogs.com/lochan/p/3307718.html