#define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1330"
#include<bits/stdc++.h>#include"library/algebra/group/Add.hpp"
#include"library/datastructure/unionfind/PotentialUnionFind.hpp"usingll=longlong;intmain(){std::ios::sync_with_stdio(false);std::cin.tie(nullptr);intn,m;while(std::cin>>n>>m,n){PotentialUnionFind<GroupAdd<ll>>uf(n);while(m--){charc;inta,b;std::cin>>c>>a>>b;a--;b--;if(c=='!'){llw;std::cin>>w;assert(uf.merge(a,b,w));}else{autoans=uf.diff(a,b);if(ans)std::cout<<ans.value()<<"\n";elsestd::cout<<"UNKNOWN\n";}}}}
#line 1 "test/AOJ/1330.test.cpp"
#define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1330"
#include<bits/stdc++.h>#line 2 "library/algebra/group/Add.hpp"
template<typenameX>structGroupAdd{usingvalue_type=X;staticconstexprXop(constX&x,constX&y)noexcept{returnx+y;}staticconstexprvoidRchop(X&x,constX&y){x+=y;}staticconstexprvoidLchop(constX&x,X&y){y+=x;}staticconstexprXinverse(constX&x)noexcept{return-x;}staticconstexprXpower(constX&x,longlongn)noexcept{returnX(n)*x;}staticconstexprXunit(){returnX(0);}staticconstexprboolcommute=true;};#line 2 "library/datastructure/unionfind/PotentialUnionFind.hpp"
template<typenameAbelGroup>classPotentialUnionFind{usingT=typenameAbelGroup::value_type;intn,num;std::vector<int>sz,parent;std::vector<T>potential;// parent[x] を基準とした時の x の値public:PotentialUnionFind()=default;PotentialUnionFind(intn):n(n),num(n),sz(n,1),parent(n,0),potential(n,AbelGroup::unit()){assert(AbelGroup::commute);std::iota(parent.begin(),parent.end(),0);}std::pair<int,T>from_root(intx){if(x==parent[x])return{x,AbelGroup::unit()};auto[r,add]=from_root(parent[x]);parent[x]=r;AbelGroup::Rchop(potential[x],add);return{r,potential[x]};}intleader(intx){returnfrom_root(x).first;}boolsame(intx,inty){assert(0<=xandx<nand0<=yandy<n);returnleader(x)==leader(y);}boolmerge(intx,inty,Td){// potential[y]-potential[x]=d にする// 矛盾する場合は変更はせず false を返すassert(0<=xandx<nand0<=yandy<n);auto[rx,dx]=from_root(x);auto[ry,dy]=from_root(y);AbelGroup::Rchop(d,dx);AbelGroup::Rchop(d,AbelGroup::inverse(dy));if(rx==ry)returnd==AbelGroup::unit();if(sz[rx]<sz[ry]){std::swap(rx,ry);d=AbelGroup::inverse(d);}sz[rx]+=sz[ry];parent[ry]=rx;potential[ry]=d;num--;returntrue;}std::optional<T>diff(intx,inty){// x を基準とするauto[rx,dx]=from_root(x);auto[ry,dy]=from_root(y);if(rx!=ry)returnstd::nullopt;returnAbelGroup::op(dy,AbelGroup::inverse(dx));}intsize(constintx){assert(0<=xandx<n);returnsz[leader(x)];}intcount()const{returnnum;}};#line 6 "test/AOJ/1330.test.cpp"
usingll=longlong;intmain(){std::ios::sync_with_stdio(false);std::cin.tie(nullptr);intn,m;while(std::cin>>n>>m,n){PotentialUnionFind<GroupAdd<ll>>uf(n);while(m--){charc;inta,b;std::cin>>c>>a>>b;a--;b--;if(c=='!'){llw;std::cin>>w;assert(uf.merge(a,b,w));}else{autoans=uf.diff(a,b);if(ans)std::cout<<ans.value()<<"\n";elsestd::cout<<"UNKNOWN\n";}}}}