#include <vector>
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

typedef long long ll;

#define SIZE 100010


struct LCA {
  int n;
  vector<vector<int>> tree, parent;
  vector<int> depth;
  int max_log;

  LCA(int n): n(n), tree(n), depth(n, -1) {
    max_log = 0;
    for (int i=1; i<=n*2; i*=2) max_log++;
    parent.assign(max_log, vector<int>(n, -1));
  }

  void add_edge(int u, int v) {
    tree[u].push_back(v);
    tree[v].push_back(u);
  }

  void dfs(int now, int p, int d) {
    parent[0][now] = p;
    depth[now] = d;

    for (int to : tree[now])
      if (to != p) dfs(to, now, d+1);
  }

  void build(int root) {
    dfs(root, -1, 0);
  }

  void build2() {
    for (int i=0; i<max_log-1; i++) {
      for (int j=0; j<n; j++)
        parent[i+1][j] = parent[i][j] == -1 ?
          -1 : parent[i][parent[i][j]];
    }
  }

  int query(int a, int b) {
    if (depth[a] > depth[b]) swap(a, b);

    for (int i=0; i<max_log; i++)
      if ((depth[b] - depth[a]) >> i & 1)
        b = parent[i][b];

    if (a == b) return a;

    for (int i=max_log-1; i>=0; i--) {
      if (parent[i][a] != parent[i][b]) {
        a = parent[i][a];
        b = parent[i][b];
      }
    }

    return parent[0][a];
  }
};

struct UnionFind{
  vector<int> data;
  UnionFind(int s): data(s, -1) {};

  int root(int x) {
    if (data[x] < 0) return x;
    return data[x] = root(data[x]);
  }

  bool set(int x, int y) {
    x = root(x);
    y = root(y);

    if (x == y) return false;

    data[x] += data[y];
    data[y] = x;
    return true;
  }

  bool check(int x, int y) {
    return root(x) == root(y);
  }
};

bool visited[SIZE];
ll dist[SIZE];
vector<pair<int,int> > G[SIZE];
pair<char, pair<int,int> > queries[SIZE];

bool dfs(int now, int back = -1, ll d=0) {
  if (visited[now]) return false;
  visited[now] = true;
  dist[now] = d;

  for (auto p : G[now]) {
    if (p.first == back) continue;
    dfs(p.first, now, d + p.second);
  }

  return true;
}

bool solve() {
  int N, M;

  scanf("%d%d", &N, &M);

  if (N == 0) return false;

  UnionFind uf(N);
  LCA lca(N);
  for (int i=0; i<N; i++) G[i].clear();


  for (int i=0; i<M; i++) {
    char c;
    int a, b, w;

    scanf(" %c%d%d", &c, &a, &b);
    a--; b--;

    if (c == '!') {
      scanf("%d", &w);

      bool f = uf.set(a, b);

      if (f) {
        G[a].push_back({b, w});
        G[b].push_back({a, -w});
        lca.add_edge(a, b);
      }
    }

    queries[i] = {c, {a, b}};
  }

  memset(visited, 0, sizeof(visited));
  for (int i=0; i<N; i++) {
    if (!visited[i]) {
      dfs(i);
      lca.build(i);
    }
  }
  lca.build2();

  UnionFind uf2(N);

  for (int i=0; i<M; i++) {
    char c = queries[i].first;
    int a = queries[i].second.first;
    int b = queries[i].second.second;

    if (c == '!') {
      uf2.set(a, b);
    } else {
      if (!uf2.check(a, b)) {
        puts("UNKNOWN");
      } else {
        int r = lca.query(a, b);
        ll A = dist[a] - dist[r];
        ll B = dist[b] - dist[r];
        ll ans = B - A;

        printf("%lld\n", ans);
      }
    }
  }

  return true;
}

int main() {

  while(solve());


}



Measured memory_bytes: 27980