#include <iostream>
#include <cstdio>
#include <vector>
#include <list>
#include <cmath>
#include <fstream>
#include <algorithm>
#include <string>
#include <queue>
#include <set>
#include <map>
#include <complex>
#include <iterator>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <stack>
#include <climits>
#include <deque>
#include <bitset>
#include <cassert>
#include <ctime>
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int dy[]={-1,0,1,0},dx[]={0,1,0,-1};
// adjust problem by problem
const double EPS=1e-8;
const double PI=acos(-1.0);
#ifdef __GNUC__
int popcount(int n){return __builtin_popcount(n);}
int popcount(ll n){return __builtin_popcountll(n);}
#endif
#ifndef __GNUC__
template<class T> int popcount(T n){int cnt=0;while(n){if(n%2)cnt++;n/=2;}return cnt;}
#endif
template<class T>int SIZE(T a){return a.size();}
template<class T>string IntToString(T num){string res;stringstream ss;ss<<num;return ss.str();}
template<class T>T StringToInt(string str){T res=0;for(int i=0;i<SIZE(str);i++)res=(res*10+str[i]-'0');return res;}
template<class T>T gcd(T a,T b){if(b==0)return a;return gcd(b,a%b);}
template<class T>T lcm(T a,T b){return a/gcd(a,b)*b;}
template<class T> void PrintSeq(T &a,int sz){for(int i=0;i<sz;i++){cout<<a[i];if(sz==i+1)cout<<endl;else cout<<' ';}}
bool EQ(double a,double b){return abs(a-b)<EPS;}
void fastStream(){cin.tie(0);std::ios_base::sync_with_stdio(0);}
vector<string> split(string str,char del){
  vector<string> res;
  for(int i=0,s=0;i<SIZE(str);i++){
    if(str[i]==del){if(i-s!=0)res.push_back(str.substr(s,i-s));s=i+1;}
    else if(i==SIZE(str)-1){res.push_back(str.substr(s));}
  }
  return res;
}

struct Query{
  int a,b,c;
  char kind;
};
Query qs[200001];

class UnionFindTree{
private:
  // indexの数の親ノード(ある集合の親を見つけたいときはここを直接参照せず、findを使う)
  vector<int> par;
  // indexを根とする木のランク
  vector<int> rank;
  // 集合のサイズ
  vector<int> cnts;
  // 木の最大値
  int treeSize;
public:
  UnionFindTree(int initTreeSize = 1000){
    // 引数で与えられた値を最大格納数とするUnionFindTreeの作成
    treeSize = initTreeSize;
    init();
  }
  void clear(){
    for(int i=0;i<treeSize;i++)
      par[i]=i,rank[i]=0,cnts[i]=1;
  }
  void init(){
    for(int i = 0; i < treeSize; i++){
      par.push_back(i);
      rank.push_back(0);
      cnts.push_back(1);
    }
  }
  // 与えられた数が格納されている木のルートを探索
  int find(int x){  
    if(par[x] == x)return x;
    else return par[x] = find(par[x]);
  }
  // 和集合をとる。ただしここでは各集合の親の付け替えは起こらない
  void unite(int x,int y){
    x = find(x);
    y = find(y);
    if(x == y)return;
    if(rank[x] < rank[y]){
      par[x] = y;
      cnts[y]+=cnts[x];
    }
    else{
      par[y] = x;
      cnts[x]+=cnts[y];
      if(rank[y] == rank[x])rank[x]++;
    }
  }
  // xの属する集合のサイズ
  int getCnt(int x){
    return cnts[find(x)];
  }
  bool same(int x,int y){
    return find(x) == find(y);
  }
    
};

struct edge{
  int to,cost;
};

int N,M;
UnionFindTree uft(200001);
vector<edge> G[200001];
bool isConnected[200001];
int vals[200001];
bool used[200001];

void bfs(int now){
  queue<pii> q;
  vals[now]=0;
  used[now]=true;
  q.push(pii(0,now));
  while(q.size()){
    pii p=q.front();q.pop();
    int ccost=p.first;
    int cpos=p.second;
    for(int i=0;i<(int)G[cpos].size();i++){
      edge &e=G[cpos][i];
      int to=e.to;
      int ncost=e.cost+ccost;
      if(!used[to]){
        vals[to]=ncost;
        used[to]=true;
        q.push(pii(ncost,to));
      }
    }
  }
}

int main(){
  fastStream();
  while(cin>>N>>M&&(N|M)){
    uft.clear();
    for(int i=0;i<N;i++)G[i].clear();
    for(int i=0;i<M;i++){
      char ch;
      int a,b,c;
      cin>>ch;
      if(ch=='?'){
        cin>>a>>b;
        a--,b--;
        isConnected[i]=uft.same(a,b);
        qs[i].a=a,qs[i].b=b,qs[i].kind=ch;
      }
      else{
        cin>>a>>b>>c;
        a--,b--;
        qs[i].a=a,qs[i].b=b,qs[i].kind=ch;
        qs[i].c=c;
        edge e;
        e.to=b;e.cost=c;
        G[a].push_back(e);e.cost*=-1;e.to=a;
        G[b].push_back(e);
        uft.unite(a,b);
      }
    }
    memset(vals,-1,sizeof(vals));
    memset(used,0,sizeof(used));
    for(int i=0;i<N;i++)if(!used[i])bfs(i);
    for(int i=0;i<M;i++){
      if(qs[i].kind=='!')continue;
      if(!isConnected[i])cout<<"UNKNOWN"<<endl;
      else{
        int a=qs[i].a,b=qs[i].b;
        cout<<-vals[a]+vals[b]<<endl;
      }
    }
  }
  return 0;
}

Measured memory_bytes: 15344