题意:

                          ! a b x 的意思告诉b-a=x...? a b的意思是询问b-a的值...若无法得到.则输出UNKNOWN..

                 题解:

      通过有要判断有无解...就能看出本题要用并查集做...关键是如何维护两者的差..用d[]记录当前点到根的距离那么对于有解的a,b..差值为d[y]-d[x]...问题转化为要维护d[]...并查集在找祖先时同时更新d[]值就好..值的注意的是一类情况..比如两个树合并..但是两个点不一定是根节点..那么就要把一个点转为根点来连接...


Program:

#include<iostream>  
#include<stdio.h>
#include<queue>
#include<stack>
#include<algorithm>
#define ll long long
#define MAXN 100005
using namespace std;
int father[MAXN];
ll d[MAXN];
int getfather(int x)
{
if (father[x]==x) return x;
int f=father[x];
father[x]=getfather(father[x]);
d[x]+=d[f];
return father[x];
}
int main()
{
int n,m,i,x,y;
ll dis;
char c;
while (~scanf("%d%d",&n,&m) && n)
{
for (i=1;i<=n;i++) father[i]=i,d[i]=0;
while (m--)
{
do { c=getchar(); }while (c!='!' && c!='?');
scanf("%d%d",&x,&y);
if (c=='?')
{
if (getfather(x)!=getfather(y)) printf("UNKNOWN\n");
else printf("%lld\n",d[y]-d[x]);
}else
{
scanf("%lld",&dis);
if (getfather(y)==getfather(x)) continue;
d[father[y]]+=dis-d[y]; //用根来连接
father[father[y]]=x;
}
}
}
return 0;
}
/*
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
4 4
! 1 2 1
! 1 3 1
! 3 4 1
? 2 4
3 3
! 1 2 100
! 1 3 50
? 2 3
3 3
! 1 3 1
! 2 3 1
? 1 2
0 0
*/