Problem:
Problem D: Room of Time and Spirit
Problem
20XX年、とある科学者がバイオテクノロジーによって強力な人造人間を開発してしまった。この人造人間はコンピュータにより、戦闘の達人たちの細胞を組み合わせて作られているため非常に強力である。
このままでは地球は人造人間に支配されてしまうので、
N
人の戦士たちは人造人間と戦うことにした。しかし今の戦士たちでは到底人造人間に敵わないため、修行をしなければならない。また、
N
人の戦士たちはそれぞれ 1 ~
N
の番号が付いている。
この時代、天空都市AIZUには SRLU室と呼ばれる修行のための特殊な部屋が存在した。この部屋での1年は外界の時間の1日と同じであるため、短期間で戦闘力を大幅に上昇することが出来る。同時に部屋に入れる人数の上限は2人である。また、その2人が部屋に入った時、それぞれ戦闘力が上昇する。
戦士たちは残された時間でどのように部屋に入るか検討するため、あなたに以下のクエリを処理するプログラムの作成を依頼した。
与えられるクエリは以下の通りである。
また以下の説明で出てくる
A
,
B
はそれぞれ戦士の番号を表す。
A
と
B
が等しい事は無い。
IN
A
B
C
A
と
B
が部屋に入り、それぞれ
C
だけ戦闘力が上昇する。この時、(部屋に入る直前の
B
の戦闘力) - (部屋に入る直前の
A
の戦闘力) =
C
が成り立つ。また、この時
B
の戦闘力は
A
の戦闘力より高い事が保証される。
COMPARE
A
B
A
と
B
の戦闘力の差 (現在の
B
の戦闘力) - (現在の
A
の戦闘力)を出力する。もしその差が特定出来なければ、WARNING と出力せよ。
Input
N
Q
query
1
.
.
.
query
Q
最初に戦士の人数
N
, クエリの数
Q
が与えられる。
次に
Q
回だけクエリが与えられる。
Constraints
入力は以下の条件を満たす。
2 ≤
N
≤ 100000
1 ≤
Q
≤ 100000
1 ≤
A
,
B
≤
N
1 ≤
C
≤ 5000
Output
上記のように与えられたクエリを順番に処理していき、 COMPAREの入力が与えられた際に出力を行う。
Sample Input1
3 5
COMPARE 1 2
IN 1 2 5
IN 2 3 3
COMPARE 2 3
COMPARE 1 3
Sample Output1
WARNING
3
11
Sample Input2
4 3
IN 1 4 10
IN 2 3 20
COMPARE 1 2
Sample Output2
WARNING
Sample Input3
3 4
IN 2 1 2
IN 3 1 2
COMPARE 1 3
COMPARE 2 3
Sample Output3
-2
2
Sample Input4
10 4
IN 10 8 2328
IN 8 4 3765
IN 3 8 574
COMPARE 4 8
Sample Output4
-3191
Sample Input5
3 5
IN 1 2 5
IN 1 2 5
IN 2 3 10
COMPARE 1 2
COMPARE 2 3
Sample Output5
15
10

Submitted solutions:

code_snippet: #include<bits/stdc++.h>

using namespace std;
int par[100001], D[100001], sum[100001];

int find(int x) {
    if (par[x] != x) {
        int px = par[x];
        par[x] = find(par[x]);
        D[x] += D[px];
        return par[x];
    }
    return x;
}

void Union(int x, int y, int c) {
    int rx = find(x);
    int ry = find(y);
    if (rx == ry)return;
    par[rx] = ry;
    D[rx] = c + D[y] - D[x];
}

void IN(int a, int b, int c) {
    sum[a] += c;
    sum[b] += c;
    Union(a, b, c - sum[b] + sum[a]);
}

string COMP(int a, int b) {
    if (find(a) != find(b))
        return "-0";
    else
        return to_string(D[a] - D[b] + sum[b] - sum[a]);
}

vector<string> huntersCombat(int n, int q, string Q[], int a[], int b[], int c[]) {
    for (int i = 1; i <= n; i++)
        par[i] = i;
    vector<string> ans;
    for (int i = 0; i < q; i++) {
        if (Q[i][0] == 'I')
            IN(a[i], b[i], c[i]);
        else {
            ans.push_back(COMP(a[i], b[i]));
        }
    }
    return ans;
}

int main() {
    int n, q;
    cin >> n >> q;
    string Q[q];
    int a[q], b[q], c[q];
    for (int i = 0; i < q; i++) {
        cin >> Q[i] >> a[i] >> b[i];
        if (Q[i][0] == 'I') {
            cin >> c[i];
        }
    }
    auto ans = huntersCombat(n, q, Q, a, b, c);
    for (auto i: ans) {
        if (i == "-0") {
            cout << "WARNING";
        } else {
            cout << i;
        }
        cout << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 100
memory_kb: 13508
final_rank: 7

code_snippet: #include<bits/stdc++.h>

using namespace std;

struct DSU {
    vector<int> szz, par, val;
    vector<vector<int>> comp;

    DSU(int n) {
        szz.resize(n + 1, 1);
        par.resize(n + 1);
        val.resize(n + 1);
        comp.resize(n + 1);
        iota(par.begin(), par.end(), 0);
        for (int i = 1; i <= n; i++) {
            comp[i].push_back(i);
        }
    }

    int find(int a) {
        while (a != par[a]) {
            a = par[a] = par[par[a]];
        }
        return a;
    }

    bool same(int a, int b) {
        return find(a) == find(b);
    }

    void merge(int a, int b, int c) {
        int parA = find(a);
        int parB = find(b);
        if (parA == parB)return;
        if (szz[parA] < szz[parB]) {
            int increament = val[b] - val[a] - c;
            for (auto node: comp[parA]) {
                val[node] += increament;
                comp[parB].push_back(node);
            }
            comp[parA].clear();
            val[a] += c;
            val[b] += c;
            szz[parB] += szz[parA];
            par[parA] = parB;
        } else {
            int increment = val[a] - val[b] + c;
            for (auto node: comp[parB]) {
                val[node] += increment;
                comp[parA].push_back(node);
            }
            comp[parB].clear();
            val[a] += c;
            val[b] += c;
            szz[parA] += szz[parB];
            par[parB] = parA;
        }
    }
};

void acc() {
    int n, q;
    cin >> n >> q;
    DSU dsu(n);
    while (q--) {
        string s;
        cin >> s;
        if (s == "IN") {
            int a, b, c;
            cin >> a >> b >> c;
            if (dsu.same(a, b)) {
                dsu.val[a] += c;
                dsu.val[b] += c;
            } else
                dsu.merge(a, b, c);
        } else {
            int a, b;
            cin >> a >> b;
            if (dsu.same(a, b)) {
                cout << dsu.val[b] - dsu.val[a] << '\n';
            } else {
                cout << "WARNING" << '\n';
            }
        }
    }
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    int t = 1;
    acc();
}
accuracy: 1
time_ms: 20
memory_kb: 10088
final_rank: 3

code_snippet: #include <iostream>
#include <algorithm>
#include <stdio.h>
#include <vector>
using namespace std;
const int maxn=100010;
long long aa[maxn];
int fa[maxn];
vector<int> v[maxn];
int fin(int x)
{
    return fa[x]==x?x:(fa[x]=fin(fa[x]));
}
int main()
{
    int n,q;
    cin>>n>>q;
    for(int i=1;i<=n;i++) fa[i]=i,v[i].push_back(i);
    string s;
    long long a,b,c;
    for(int i=0;i<q;i++){
        cin>>s>>a>>b;
        if(s[0]=='I'){
            cin>>c;
            if(fin(a)==fin(b)){
                aa[a]+=c;
                aa[b]+=c;
            }
            else{
                int fro=fin(a);
                int to=fin(b);
                int cha=aa[b]-c-aa[a];
                for(int j=0;j<(int)v[fro].size();j++){
                    aa[v[fro][j]]+=cha;
                    v[to].push_back(v[fro][j]);
                }
                aa[a]+=c;
                aa[b]+=c;
                fa[fro]=fa[to];
            }
        }
        if(s[0]=='C'){
            if(fin(a)!=fin(b)){
                cout<<"WARNING"<<endl;
            }
            else{
                cout<<aa[b]-aa[a]<<endl;
            }
        }
        //for(int j=1;j<=n;j++){
        //    cout<<v[j].size()<<endl;
        //}
        //for(int j=1;j<=n;j++){
        //    cout<<fa[j]<<" ";
        //}
        //cout<<endl;
    }
    return 0;
}
accuracy: 1
time_ms: 160
memory_kb: 56892
final_rank: 16

code_snippet: #include <algorithm>
#include <iostream>
#include <vector>
#include <numeric>
using namespace std;

template<typename T>
struct WeightedQuickFind {
    vector<int> par;
    vector<T> weight;
    vector<vector<int>> groups;
    WeightedQuickFind(int sz) : par(sz), weight(sz) {
        iota(begin(par), end(par), 0);
        for (int i = 0; i < sz; i++) groups.emplace_back(1, i);
    }
    void merge(int x, int y, T w) {
        if (par[x] == par[y]) return ;
        if (groups[par[x]].size() > groups[par[y]].size()) swap(x, y), w = -w;
        int p = par[x];
        w += weight[x] - weight[y];
        for (int i: groups[par[x]]) {
            weight[i] -= w, par[i] = par[y], groups[par[y]].emplace_back(i);
        }
        groups[p].clear();
    }
    bool is_same(int x, int y) { return par[x] == par[y]; }
    T diff(int x, int y) { return weight[y] - weight[x]; }
    void update(int x, int y, T w) {
        weight[x] += w, weight[y] += w;
        if (par[x] != par[y]) merge(x, y, w);
    }
};

int main() {
    int n, q; cin >> n >> q;
    WeightedQuickFind<int> wqf(n);
    while (q--) {
        string s; cin >> s;
        int a, b; cin >> a >> b; a--, b--;
        if (s[0] == 'I') {
            int c; cin >> c;
            wqf.update(a, b, c);
        }
        if (s[0] == 'C') {
            if (wqf.is_same(a, b)) {
                cout << wqf.diff(a, b) << endl;
            } else {
                cout << "WARNING" << endl;
            }
        }
    }
    return 0;
}
accuracy: 1
time_ms: 150
memory_kb: 9480
final_rank: 11

code_snippet: #include <algorithm>
#include <iostream>
#include <vector>
#include <numeric>
using namespace std;

template<typename T>
struct WeightedQuickFind {
    vector<int> par;
    vector<T> weight;
    vector<vector<int>> groups;
    WeightedQuickFind(int sz) : par(sz), weight(sz), groups(sz) {
        iota(begin(par), end(par), 0);
        for (int i = 0; i < sz; i++) groups[i].assign(1, i);
    }
    void merge(int x, int y, T w) {
        if (x == y) return ;
        if (groups[par[x]].size() > groups[par[y]].size()) swap(x, y), w = -w;
        int p = par[x];
        w += weight[x] - weight[y];
        for (int i: groups[par[x]]) {
            weight[i] -= w, par[i] = par[y], groups[par[y]].emplace_back(i);
        }
        groups[p].clear();
    }
    bool is_same(int x, int y) { return par[x] == par[y]; }
    T diff(int x, int y) { return weight[y] - weight[x]; }
    void update(int x, int y, T w) {
        weight[x] += w, weight[y] += w;
        if (par[x] != par[y]) merge(x, y, w);
    }
};

int main() {
    int n, q; cin >> n >> q;
    WeightedQuickFind<int> wqf(n);
    while (q--) {
        string s; cin >> s;
        int a, b; cin >> a >> b; a--, b--;
        if (s[0] == 'I') {
            int c; cin >> c;
            wqf.update(a, b, c);
        }
        if (s[0] == 'C') {
            if (wqf.is_same(a, b)) {
                cout << wqf.diff(a, b) << endl;
            } else {
                cout << "WARNING" << endl;
            }
        }
    }
    return 0;
}
accuracy: 1
time_ms: 150
memory_kb: 9372
final_rank: 10

code_snippet: #include <algorithm>
#include <iostream>
#include <vector>
#include <numeric>
using namespace std;

template<typename T>
struct WeightedQuickFind {
    vector<int> par;
    vector<T> weight;
    vector<vector<int>> groups;
    WeightedQuickFind(int sz) : par(sz), weight(sz) {
        iota(begin(par), end(par), 0);
        for (int i = 0; i < sz; i++) groups.emplace_back(1, i);
    }
    void merge(int x, int y, T w) {
        if (x == y) return ;
        if (groups[par[x]].size() > groups[par[y]].size()) swap(x, y), w = -w;
        int p = par[x];
        w += weight[x] - weight[y];
        for (int i: groups[par[x]]) {
            weight[i] -= w, par[i] = par[y], groups[par[y]].emplace_back(i);
        }
        groups[p].clear();
    }
    bool is_same(int x, int y) { return par[x] == par[y]; }
    T diff(int x, int y) { return weight[y] - weight[x]; }
    void update(int x, int y, T w) {
        weight[x] += w, weight[y] += w;
        if (par[x] != par[y]) merge(x, y, w);
    }
};

int main() {
    int n, q; cin >> n >> q;
    WeightedQuickFind<int> wqf(n);
    while (q--) {
        string s; cin >> s;
        int a, b; cin >> a >> b; a--, b--;
        if (s[0] == 'I') {
            int c; cin >> c;
            wqf.update(a, b, c);
        }
        if (s[0] == 'C') {
            if (wqf.is_same(a, b)) {
                cout << wqf.diff(a, b) << endl;
            } else {
                cout << "WARNING" << endl;
            }
        }
    }
    return 0;
}
accuracy: 1
time_ms: 150
memory_kb: 9500
final_rank: 12

code_snippet: #include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

template<typename T>
struct WeightedUnionFind {
    vector<int> data;
    vector<T> ws;
    WeightedUnionFind(int sz) : data(sz, -1), ws(sz) { }
    bool merge(int x, int y, T w) {             // ws(y) = ws(x) + w
        w += weight(x); w -= weight(y);
        if ((x = root(x)) == (y = root(y))) return false;
        if (data[x] > data[y]) swap(x, y), w = -w;
        data[x] += data[y]; data[y] = x; ws[y] = w;
        return true;
    }
    bool is_same(int x, int y) { return root(x) == root(y); }
    T diff(int x, int y) { return weight(y) - weight(x); }
    T weight(int t) { root(t); return ws[t]; }
    int root(int k) {
        if (data[k] < 0) return k;
        int par = root(data[k]);
        ws[k] += ws[data[k]];
        return data[k] = par;
    }
};

int main() {
    int n, q; cin >> n >> q;
    WeightedUnionFind<int> wuf(n);
    vector<int> added(n);
    while (q--) {
        string s; cin >> s;
        int a, b; cin >> a >> b; a--, b--;
        if (s[0] == 'I') {
            int c; cin >> c;
            wuf.merge(a, b, c + added[a] - added[b]);
            added[a] += c, added[b] += c;
        }
        if (s[0] == 'C') {
            if (wuf.is_same(a, b)) {
                cout << wuf.diff(a, b) + added[b] - added[a] << endl;
            } else {
                cout << "WARNING" << endl;
            }
        }
    }
    return 0;
}
accuracy: 1
time_ms: 150
memory_kb: 3832
final_rank: 4

code_snippet: #include <bits/stdc++.h>
using namespace std;

int n, q, a, b, c;
string req;
vector<int> ls[100005];

template <class T>
struct Unionfind {
  //木の番号
  vector<int> par;
  //木の階層
  vector<int> treerank;
  //辺の重み
  vector<T> weight;
  //コンストラクタ
  Unionfind(int n = 1, T initialnum = 0) {
    stree(n + 1, initialnum);
  }
  //木の生成、初期化
  void stree(int n = 1, T initialnum = 0) {
    par.resize(n);
    treerank.resize(n);
    weight.resize(n);
    for(int i = 0; i < n; ++i) {
      par[i] = i;
      treerank[i] = 0;
      weight[i] = initialnum;
      ls[i].push_back(i);
    }
  }
  //木の根を調べる
  int root(int x) {
    if(par[x] == x) return x;
    int rx = root(par[x]);
    weight[x] += weight[par[x]];
    return par[x] = rx;
  }
  //同一の木にあるか調べる
  bool chtree(int x, int y) { return root(x) == root(y); }
  //重み計算
  T calcw(int x) {
    root(x);
    return weight[x];
  }
  //木に追加
  //すでに同じグループにいた場合、計算せずに0を返す。
  bool unitree(int x, int y, T w = 0) {
    for(int i = 0; i < ls[y].size(); ++i)
      if(par[ls[y][i]] == y) weight[ls[y][i]] -= w;

    for(int i = 0; i < ls[x].size(); ++i)
      if(par[ls[x][i]] == x) weight[ls[x][i]] -= w;

    weight[x] += w;
    weight[y] += w;
    w += calcw(x);
    w -= calcw(y);
    x = root(x);
    y = root(y);

    if(x == y) return 0;
    if(treerank[x] < treerank[y]) {
      ls[y].insert(ls[y].end(), ls[x].begin(), ls[x].end());
      par[x] = y;
      weight[x] = -w;
    }
    else if(treerank[y] < treerank[x]) {
      ls[x].insert(ls[x].end(), ls[y].begin(), ls[y].end());
      par[y] = x;
      weight[y] = w;
    }
    else {
      ls[x].insert(ls[x].end(), ls[y].begin(), ls[y].end());
      par[y] = x;
      ++treerank[x];
      weight[y] = w;
    }
    return 1;
  }
  // xとyの差を計算
  //もしxとyが同じグループになかったら-1を返す
  T calcdiff(int x, int y) {
    if(!chtree(x, y)) return -1;
    return calcw(y) - calcw(x);
  }
};

int main() {
  int i;
  cin >> n >> q;
  Unionfind<int> uf(n);
  for(i = 0; i < q; ++i) {
    cin >> req;
    if(req == "IN") {
      cin >> a >> b >> c;
      uf.unitree(a, b, c);
    }
    else {
      int ans;
      cin >> a >> b;
      ans = uf.calcdiff(a, b);
      if(!uf.chtree(a,b))
        cout << "WARNING"<<endl;
      else
        cout << ans << endl;
    }
  }
}
accuracy: 1
time_ms: 140
memory_kb: 9736
final_rank: 9

code_snippet: #include <bits/stdc++.h>
using namespace std;

int n, q, a, b, c;
string req;
vector<int> ls[100005];

template <class T>
struct Unionfind {
  //木の番号
  vector<int> par;
  //木の階層
  vector<int> treerank;
  //辺の重み
  vector<T> weight;
  //コンストラクタ
  Unionfind(int n = 1, T initialnum = 0) {
    stree(n + 1, initialnum);
  }
  //木の生成、初期化
  void stree(int n = 1, T initialnum = 0) {
    par.resize(n);
    treerank.resize(n);
    weight.resize(n);
    for(int i = 0; i < n; ++i) {
      par[i] = i;
      treerank[i] = 0;
      weight[i] = initialnum;
      ls[i].push_back(i);
    }
  }
  //木の根を調べる
  int root(int x) {
    if(par[x] == x) return x;
    int rx = root(par[x]);
    weight[x] += weight[par[x]];
    return par[x] = rx;
  }
  //同一の木にあるか調べる
  bool chtree(int x, int y) { return root(x) == root(y); }
  //重み計算
  T calcw(int x) {
    root(x);
    return weight[x];
  }
  //木に追加
  //すでに同じグループにいた場合、計算せずに0を返す。
  bool unitree(int x, int y, T w = 0) {
    for(int i = 0; i < ls[y].size(); ++i)
      if(par[ls[y][i]] == y) weight[ls[y][i]] -= w;

    for(int i = 0; i < ls[x].size(); ++i)
      if(par[ls[x][i]] == x) weight[ls[x][i]] -= w;

    weight[x] += w;
    weight[y] += w;
    w += calcw(x);
    w -= calcw(y);
    x = root(x);
    y = root(y);

    if(x == y) return 0;
    if(treerank[x] < treerank[y]) {
      ls[y].insert(ls[y].end(), ls[x].begin(), ls[x].end());
      par[x] = y;
      weight[x] = -w;
    }
    else if(treerank[y] < treerank[x]) {
      ls[x].insert(ls[x].end(), ls[y].begin(), ls[y].end());
      par[y] = x;
      weight[y] = w;
    }
    else {
      ls[x].insert(ls[x].end(), ls[y].begin(), ls[y].end());
      par[y] = x;
      ++treerank[x];
      weight[y] = w;
    }
    return 1;
  }
  // xとyの差を計算
  //もしxとyが同じグループになかったら-1を返す
  T calcdiff(int x, int y) {
    if(!chtree(x, y)) return -1;
    return calcw(y) - calcw(x);
  }
};

int main() {
  int i;
  cin >> n >> q;
  Unionfind<int> uf(n);
  for(i = 0; i < q; ++i) {
    cin >> req;
    if(req == "IN") {
      cin >> a >> b >> c;
      uf.unitree(a, b, c);
    }
    else {
      int ans;
      cin >> a >> b;
      ans = uf.calcdiff(a, b);
      if(ans == -1)
        cout << "WARNING"<<endl;
      else
        cout << ans << endl;
    }
  }
}
accuracy: 0.3181818181818182
time_ms: 130
memory_kb: 9788
final_rank: 17

code_snippet: #include <bits/stdc++.h>
using namespace std;

int n, q, a, b, c;
string req;
vector<int> ls[100005];

template <class T>
struct Unionfind {
  //木の番号
  vector<int> par;
  //木の階層
  vector<int> treerank;
  //辺の重み
  vector<T> weight;
  //コンストラクタ
  Unionfind(int n = 1, T initialnum = 0) {
    stree(n + 1, initialnum);
  }
  //木の生成、初期化
  void stree(int n = 1, T initialnum = 0) {
    par.resize(n);
    treerank.resize(n);
    weight.resize(n);
    for(int i = 0; i < n; ++i) {
      par[i] = i;
      treerank[i] = 0;
      weight[i] = initialnum;
      ls[i].push_back(i);
    }
  }
  //木の根を調べる
  int root(int x) {
    if(par[x] == x) return x;
    int rx = root(par[x]);
    weight[x] += weight[par[x]];
    return par[x] = rx;
  }
  //同一の木にあるか調べる
  bool chtree(int x, int y) { return root(x) == root(y); }
  //重み計算
  T calcw(int x) {
    root(x);
    return weight[x];
  }
  //木に追加
  //すでに同じグループにいた場合、計算せずに0を返す。
  bool unitree(int x, int y, T w = 0) {
    T ww = w;
    for(int i = 0; i < ls[y].size(); ++i) {
      weight[ls[y][i]] -= ww;
    }
    for(int i = 0; i < ls[x].size(); ++i) {
      weight[ls[x][i]] -= ww;
    }
    weight[x] += ww;
    weight[y] += ww;
    w += calcw(x);
    w -= calcw(y);
    x = root(x);
    y = root(y);

    if(x == y) return 0;
    if(treerank[x] < treerank[y]) {
      ls[y].insert(ls[y].end(), ls[x].begin(), ls[x].end());
      ls[x].erase(ls[x].begin(), ls[x].end());
      par[x] = y;
      weight[x] = -w;
    }
    else if(treerank[y] < treerank[x]) {
      ls[x].insert(ls[x].end(), ls[y].begin(), ls[y].end());
      ls[y].erase(ls[y].begin(), ls[y].end());
      par[y] = x;
      weight[y] = w;
    }
    else {
      ls[x].insert(ls[x].end(), ls[y].begin(), ls[y].end());
      ls[y].erase(ls[y].begin(), ls[y].end());
      par[y] = x;
      ++treerank[x];
      weight[y] = w;
    }
    return 1;
  }
  // xとyの差を計算
  //もしxとyが同じグループになかったら-1を返す
  T calcdiff(int x, int y) {
    if(!chtree(x, y)) return -1;
    return calcw(y) - calcw(x);
  }
};

int main() {
  int i;
  cin >> n >> q;
  Unionfind<int> uf(n);
  for(i = 0; i < q; ++i) {
    cin >> req;
    if(req == "IN") {
      cin >> a >> b >> c;
      uf.unitree(a, b, c);
    }
    else {
      int ans;
      cin >> a >> b;
      ans = uf.calcdiff(a, b);
      if(ans == -1)
        cout << "WARNING"<<endl;
      else
        cout << ans << endl;
    }
  }
}
accuracy: 0.18181818181818182
time_ms: 130
memory_kb: 5496
final_rank: 18

code_snippet: #include <bits/stdc++.h>
#define REP(i, a, n) for(ll i = ((ll) a); i < ((ll) n); i++)
using namespace std;
typedef long long ll;

class UnionFind {
public:
  vector<ll> parent, gap, up;

  UnionFind(ll n): parent(n), gap(n), up(n) {
    REP(i, 0, n) parent[i] = i;
  }

  ll find(ll i) {
    if(parent[i] == i) return i;
    ll p = parent[i];
    ll t = find(p);
    gap[i] += gap[p];
    return parent[i] = t;
  }

  void unite(ll a, ll b, ll c) {
    ll pa = find(a), pb = find(b);
    if(pa != pb) {
      ll w = height(a) - height(b) + c;
      gap[pa] = -w;
      parent[pa] = find(pb);
    }
    up[a] += c;
    up[b] += c;
  }

  ll height(ll i) {
    return gap[i] + up[i];
  }
};

int main(void) {
  ll N, Q;
  cin >> N >> Q;
  vector<ll> T(Q), A(Q), B(Q), C(Q);
  REP(i, 0, Q) {
    string type;
    cin >> type >> A[i] >> B[i]; A[i]--; B[i]--;
    if(type == "IN") {
      T[i] = 0;
      cin >> C[i];
    }
    if(type == "COMPARE") T[i] = 1;
  }

  UnionFind uf(N);
  REP(i, 0, Q) {
    if(T[i] == 0) {
      uf.unite(A[i], B[i], C[i]);
    } else {
      if(uf.find(A[i]) != uf.find(B[i])) {
        cout << "WARNING" << endl;
      } else {
        cout << uf.height(B[i]) - uf.height(A[i]) << endl;
      }
    }
  }
}
accuracy: 1
time_ms: 160
memory_kb: 8468
final_rank: 13

code_snippet: #include<iostream>
#include <list>
#include<stack>
#include<queue>
#include <vector>
#include <set>
#include<algorithm>
#include<math.h>
#include<stdlib.h>
#include<string>
#include <functional>
#include<fstream>

#define FOR(k,m,n) for(int (k)=(m);(k)<(n);(k)++)
#define LL long long
#define CLR(a) memset((a),0,sizeof(a))
#define SZ(x) (int((x).size()))
#define WAITING(str) int str;std::cin>>str;
#define DEBUGING(str) cout<<str<<endl
using namespace std;

const LL MOD = 1000000007;// 10^9+7
const int INF = (1 << 30);
#define REP(i, a, n) for(ll i = ((ll) a); i < ((ll) n); i++)
using namespace std;
typedef long long ll;

class UnionFind {
public:
	vector<ll> parent;
	vector<ll> gap;//強化前の、素の値
	vector<ll> up;//強化量

	UnionFind(ll n) : parent(n), gap(n, 0), up(n, 0) {
		REP(i, 0, n) parent[i] = i;
	}

	ll find(ll i) {
		if (parent[i] == i) return i;

		int tmp = parent[i];
		ll p = find(parent[i]);
		//cerr << "find  " << i+1 << " ,," << tmp+1 << "p: " << p+1 << endl;
		gap[i] += gap[tmp];
		return parent[i] = p;
	}

	void unite(ll i, ll j, ll c) {
		ll p = find(i), q = find(j);
		if (p != q) {
			gap[p] = c + get(j) - get(i);
			parent[p] = q;
		}
		up[i] += c;
		up[j] += c;
	}

	ll get(ll i) {
		return  - up[i] + gap[i];
		//return up[find(i)] - up[i] + gap[i];
	}
};

int main(void) {
	ll N, Q;
	cin >> N >> Q;
	vector<ll> T(Q), A(Q), B(Q), C(Q);
	REP(i, 0, Q) {
		string type;
		cin >> type >> A[i] >> B[i]; A[i]--; B[i]--;
		if (type == "IN") {
			T[i] = 0;
			cin >> C[i];
		}
		if (type == "COMPARE") T[i] = 1;
	}

	UnionFind uf(N);
	REP(i, 0, Q) {
		//cerr << endl<<endl<<"   debug" << endl;
		if (T[i] == 0) {
			uf.unite(A[i], B[i], C[i]);
		}
		if (T[i] == 1) {
			if (uf.find(A[i]) != uf.find(B[i])) cout << "WARNING" << endl;
			else {
				//uf.find(A[i]);
				//uf.find(B[i]);
				//cerr << "testing" << endl;
				cout << uf.get(A[i]) - uf.get(B[i]) << endl;
			}
		}
		//cerr << "====" << endl;
		//cerr << "way::" << A[i]+1 << " " << B[i]+1 << endl;
		//REP(i, 0, N) cerr <<"me:"<<i+1<< " par:" << uf.parent[i] + 1 << ",  gap:" << uf.gap[i] << ",  up:" << uf.up[i] << endl;
	}
	//cerr << "==FINISH==" << endl;
	//REP(i, 0, N) cerr << "par:" << uf.parent[i] << ",  gap:" << uf.gap[i] << ",  up:" << uf.up[i] << endl;
	int n;
	cin >> n;

}
accuracy: 1
time_ms: 150
memory_kb: 8372
final_rank: 8

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define _MACRO(_1, _2, _3, NAME, ...) NAME
#define _repl(i,a,b) for(int i=(int)(a);i<(int)(b);i++)
#define _rep(i,n) _repl(i,0,n)
#define rep(...) _MACRO(__VA_ARGS__, _repl, _rep)(__VA_ARGS__)
#define pb push_back
#define all(x) begin(x),end(x)
#define uniq(x) sort(all(x)),(x).erase(unique(all(x)),end(x))
#ifdef LOCAL
#define dbg(...) _dbg(#__VA_ARGS__, __VA_ARGS__)
void _dbg(string){cerr<<endl;}
template<class H,class... T> void _dbg(string s,H h,T... t){int l=s.find(',');cerr<<s.substr(0,l)<<" = "<<h<<", ";_dbg(s.substr(l+1),t...);}
template<class T,class U> ostream& operator<<(ostream &o, const pair<T,U> &p){o<<"("<<p.fi<<","<<p.se<<")";return o;}
template<class T> ostream& operator<<(ostream &o, const vector<T> &v){o<<"[";for(T t:v){o<<t<<",";}o<<"]";return o;}
#else
#define dbg(...) {}
#endif

#define long long long // for codeforces

template <class T>
class WeightedUnionFind {
  int n;
  vector<int> par,sz;
  vector<T> w;
  // weight[i] : iがpar[i]よりどれだけ重いか
public:
  WeightedUnionFind(){}
  WeightedUnionFind(int _n) : n(_n) {
    par.resize(n, -1);
    sz.resize(n, 1);
    w.resize(n, 0);
  }
  int find(int i){
    if(par[i] < 0) return i;
    int p = find(par[i]);
    w[i] += w[par[i]];
    return par[i] = p;
  }
  T weight(int x){ find(x); return w[x]; }
  bool same(int x, int y){ return find(x) == find(y); }
  // weight[i] +w の位置に j を配置
  void unite(int i, int j, T nw){
    nw += weight(i) - weight(j);
    int x = find(i), y = find(j);
    if(x == y) return;
    if(sz[x] < sz[y]){
      swap(x, y);
      nw = -nw;
    }
    sz[x] += sz[y];
    par[y] = x;
    w[y] = nw;
  }
  // x からみた y の相対位置
  T diff(int x, int y){ return weight(y) - weight(x); }
};

int main(){
  int n,q;
  scanf("%d %d", &n, &q);

  WeightedUnionFind<int> uf(n);
  vector<int> added(n, 0);
  rep(i,q){
    char s[20];
    scanf("%s", s);
    if(s[0] == 'I') {
      int a,b,c;
      scanf("%d %d %d", &a, &b, &c);
      a--;b--;
      uf.unite(a, b, c + added[a] - added[b]);
      added[a] += c;
      added[b] += c;
    }
    else if(s[0] == 'C') {
      int a,b;
      scanf("%d %d", &a, &b);
      a--;b--;
      if(uf.same(a,b)) { dbg(added, uf.weight(0), uf.weight(1), uf.weight(2));
        printf("%d\n", uf.diff(a,b) + added[b] - added[a]);
      } else {
        printf("WARNING\n");
      }
    }
    else assert(false);
  }

  return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 4408
final_rank: 2

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i))
#define all(x) (x).begin(),(x).end()
#define pb push_back
#define fi first
#define se second

struct UnionFind{
    int n;
    vector<int> d;
    vector<ll> w;
    UnionFind(){}
    UnionFind(int N):n(N),d(N,-1),w(N,0){}
    int root(int v){
        if(d[v]<0) return v;
        return root(d[v]);
    }
    ll calc(int v){
        if(d[v]<0)return 0;
        return calc(d[v])+w[v];
    }
    bool unite(int X, int Y, int W){
        ll A=calc(X);
        ll C=calc(Y);
        X = root(X); Y = root(Y);
        if(X==Y) return false;
        if(size(X) < size(Y)){
            swap(X,Y);
            W=-W;
            swap(A,C);
        }
        ll B=W+A-C;
        w[Y]=B;
        d[X] += d[Y];
        d[Y] = X;
        return true;
    }
    int size(int v){ return -d[root(v)]; }
    bool same(int X, int Y){ return root(X)==root(Y); }
};

int n,q;
ll sum[100010];

int main(){
    cin>>n>>q;
    UnionFind uf(n);
    rep(i,q){
        string s;
        cin>>s;
        if(s=="COMPARE"){
            int a,b;
            cin>>a>>b;
            a--;b--;
            if(uf.root(a)!=uf.root(b)){
                cout<<"WARNING"<<endl;
                continue;
            }
            ll va=uf.calc(a)+sum[a];
            ll vb=uf.calc(b)+sum[b];
            cout<<vb-va<<endl;
        }else if(s=="IN"){
            int a,b,c;
            cin>>a>>b>>c;
            a--;b--;
            uf.unite(a,b,c-(sum[b]-sum[a]));
            sum[a]+=c;
            sum[b]+=c;
        }
    }
    return 0;
}
accuracy: 1
time_ms: 150
memory_kb: 4816
final_rank: 5

code_snippet: #include<iostream>
#include<string>
#include<algorithm>
#include<vector>
#include<iomanip>
#include<math.h>
#include<queue>
#include<deque>
#include<map>
#include<set>
#include<bitset>
using namespace std;
#define REP(i,m,n) for(int i=(int)m ; i < (int) n ; i++ )
#define rep(i,n) REP(i,0,n)
typedef long long ll;
typedef pair<ll,int> pint;
const int inf=1e9+7;
const ll longinf=1LL<<60;
const ll mod=1e9+7;
int dx[4]={1,0,-1,0} , dy[4]={0,1,0,-1};

ll r[101010], p[101010], par[101010];

int find(int x){
    if(par[x]==x)
        return x;
    int y = find(par[x]);
    r[x] += r[par[x]];
    return par[x] = y;
}

ll weight(int x){
    find(x);
    return r[x] + p[x];
}

void unite(int x, int y, int c){
    p[x] += c;
    p[y] += c;
    c -= weight(y);
    c += weight(x);
    x = find(x);
    y = find(y);
    if(x!=y){
        par[x] = y;
        r[x] = -c;
    }
}
int main(){
    int n, q;
    cin >> n >> q;
    rep(i, n) par[i] = i;
    rep(i,q){
        string s;
        cin >> s;
        if(s=="COMPARE"){
            int x, y;
            cin >> x >> y;
            if(find(x-1)!=find(y-1))
                cout << "WARNING" << "\n";
            else cout << weight(y - 1) - weight(x - 1) << "\n";
        }
        else{
            int x, y, c;
            cin >> x >> y >> c;
            unite(x - 1, y - 1, c);
        }
    }
    return 0;
}
accuracy: 1
time_ms: 160
memory_kb: 5372
final_rank: 6

code_snippet: #include <cstdio>
#include <cstdint>
#include <algorithm>
#include <string>
#include <vector>
#include <numeric>
#include <stdexcept>

template <class Weight>
class WeightedQuickFind {
  std::vector<std::vector<size_t>> groups;
  std::vector<size_t> ind;
  std::vector<Weight> weight;

public:
  WeightedQuickFind(size_t n): ind(n), weight(n) {
    std::iota(ind.begin(), ind.end(), 0);
    for (size_t i=0; i<n; ++i)
      groups.emplace_back(1, i);
  }

  struct NotConnected: public std::logic_error {
    NotConnected(): std::logic_error("") {}
  };

  void unite(size_t u, size_t v, Weight w) {
    // (weight of u) - (weight of v) = w
    if (u == v) return;
    if (groups[ind[u]].size() > groups[ind[v]].size()) {
      std::swap(u, v);
      w = -w;
    }
    size_t pi=ind[u];
    // weight[u] <- weight[v]+w
    Weight x=weight[v]+w-weight[u];
    for (size_t i: groups[ind[u]]) {
      weight[i] += x;
      ind[i] = ind[v];
      groups[ind[v]].emplace_back(i);
    }
    groups[pi].clear();
  }

  Weight diff(size_t u, size_t v) const {
    if (ind[u] != ind[v])
      throw NotConnected();

    return weight[u]-weight[v];
  }

  void update(size_t u, size_t v, Weight w) {
    weight[u] += w;
    weight[v] += w;
    if (ind[u] != ind[v])
      unite(u, v, w);
  }

  void debug() const {
    fprintf(stderr, "Weight:\n");
    for (size_t i=0; i<weight.size(); ++i)
      fprintf(stderr, "%d%c", weight[i], i+1<weight.size()? ' ':'\n');

    fprintf(stderr, "Index:\n");
    for (size_t i=0; i<ind.size(); ++i)
      fprintf(stderr, "%zu%c", ind[i], i+1<ind.size()? ' ':'\n');

    fprintf(stderr, "groups:\n");
    for (size_t i=0; i<groups.size(); ++i) {
      fprintf(stderr, "{");
      for (size_t j=0; j<groups[i].size(); ++j) {
        fprintf(stderr, "%zu%s", groups[i][j], j+1<groups[i].size()? ", ":"");
      }
      fprintf(stderr, "}%s", i+1<groups.size()? ", ":"\n");
    }
    fprintf(stderr, "\n");
  }
};

int main() {
  size_t N;
  int Q;
  scanf("%zu %d", &N, &Q);

  WeightedQuickFind<int> uf(N);
  for (int i=0; i<Q; ++i) {
    char s[8];
    scanf("%s", s);
    if (s[0] == 'I') {
      size_t u, v;
      int w;
      scanf("%zu %zu %d", &u, &v, &w);
      --u, --v;
      uf.update(v, u, w);
    } else {
      size_t u, v;
      scanf("%zu %zu", &u, &v);
      --u, --v;
      try {
        printf("%d\n", uf.diff(v, u));
      } catch (WeightedQuickFind<int>::NotConnected) {
        printf("WARNING\n");
      }
    }
  }
}
accuracy: 1
time_ms: 150
memory_kb: 10152
final_rank: 14

code_snippet: #include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

const long long int INF = 1LL << 60;
template<typename Type>
struct QuickFind {
  int N;
  vector<int> i2g;
  vector< vector<int> > g2i;
  vector<Type> weight;

  QuickFind(int N_) {
    N = N_;
    i2g.resize(N);
    g2i.resize(N);
    weight.resize(N);

    for(int i=0; i<N; i++) {
      i2g[i] = i;
      g2i[i] = vector<int>{i};
    }
  }
  bool same(int u, int v) {
    return i2g[u] == i2g[v];
  }
  void merge(int u, int v, Type w) {
    int ru = i2g[u], rv = i2g[v];

    // merge v into u
    if(g2i[ru].size() < g2i[rv].size()) {
      swap(u, v);
      swap(ru, rv);
      w = -w;
    }

    Type cost = weight[v];
    weight[u] += abs(w);
    weight[v] = weight[u] + w;
    
    for(auto e : g2i[rv]) {
      i2g[e] = ru;
      Type diff = weight[e] - cost;
      if(e != u && e != v) {
        weight[e] = weight[v] - abs(w) + diff;
      }
    }
    
    if(ru != rv) {
      g2i[ru].insert(g2i[ru].end(), g2i[rv].begin(), g2i[rv].end());
      g2i[rv].clear();
    }
  }
  Type calc_weight(int u, int v) {
    if(!same(u, v)) return INF;
    return weight[v] - weight[u];
  }
};

int main() {
  int N, Q; cin >> N >> Q;

  QuickFind<long long int> qf(N);
  for(int i=0; i<Q; i++) {
    string query; cin >> query;

    if(query == "COMPARE") {
      int u, v; cin >> u >> v;
      u--; v--;
      long long int ans = qf.calc_weight(u, v);
      if(ans == INF) cout << "WARNING" << endl;
      else cout << ans << endl;
    }
    else {
      int u, v, w; cin >> u >> v >> w;
      u--; v--;
      qf.merge(u, v, w);
    }
  }
  return 0;
}
accuracy: 1
time_ms: 430
memory_kb: 9824
final_rank: 15

code_snippet: #include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

const long long int INF = 1LL << 60;
template<typename Type>
struct QuickFind {
  int N;
  vector<int> i2g;
  vector< vector<int> > g2i;
  vector<Type> weight;

  QuickFind(int N_) {
    N = N_;
    i2g.resize(N);
    g2i.resize(N);
    weight.resize(N);

    for(int i=0; i<N; i++) {
      i2g[i] = i;
      g2i[i] = vector<int>{i};
    }
  }
  bool same(int u, int v) {
    return i2g[u] == i2g[v];
  }
  void merge(int u, int v, Type w) {
    int ru = i2g[u], rv = i2g[v];

    // merge v into u
    if(g2i[ru].size() < g2i[rv].size()) {
      swap(u, v);
      swap(ru, rv);
      w = -w;
    }

    Type cost = weight[v];
    weight[u] += abs(w);
    weight[v] = weight[u] + w;
    
    for(auto e : g2i[rv]) {
      i2g[e] = ru;
      Type diff = weight[e] - cost;
      if(e != u && e != v) {
        weight[e] = weight[u] + diff;
      }
    }
    
    if(ru != rv) {
      g2i[ru].insert(g2i[ru].end(), g2i[rv].begin(), g2i[rv].end());
      g2i[rv].clear();
    }
  }
  Type calc_weight(int u, int v) {
    if(!same(u, v)) return INF;
    return weight[v] - weight[u];
  }
};

int main() {
  int N, Q; cin >> N >> Q;

  QuickFind<long long int> qf(N);
  for(int i=0; i<Q; i++) {
    string query; cin >> query;

    if(query == "COMPARE") {
      int u, v; cin >> u >> v;
      u--; v--;
      long long int ans = qf.calc_weight(u, v);
      if(ans == INF) cout << "WARNING" << endl;
      else cout << ans << endl;
    }
    else {
      int u, v, w; cin >> u >> v >> w;
      u--; v--;
      qf.merge(u, v, w);
    }
  }
  return 0;
}
accuracy: 0.18181818181818182
time_ms: 150
memory_kb: 3224
final_rank: 19

code_snippet: #include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

const long long int INF = 1LL << 60;
template<typename Type>
struct QuickFind {
  int N;
  vector<int> i2g;
  vector< vector<int> > g2i;
  vector<Type> weight;

  QuickFind(int N_) {
    N = N_;
    i2g.resize(N);
    g2i.resize(N);
    weight.resize(N);

    for(int i=0; i<N; i++) {
      i2g[i] = i;
      g2i[i] = vector<int>{i};
    }
  }
  bool same(int u, int v) {
    return i2g[u] == i2g[v];
  }
  void merge(int u, int v, int w) {
    int ru = i2g[u], rv = i2g[v];

    // merge v into u
    if(g2i[ru].size() < g2i[rv].size()) {
      swap(u, v);
      swap(ru, rv);
      w = -w;
    }

    for(auto e : g2i[rv]) {
      i2g[e] = ru;
      Type diff = weight[e] - weight[v];
      weight[e] = weight[u] + w + diff;
    }

    if(ru != rv) {
      g2i[ru].insert(g2i[ru].end(), g2i[rv].begin(), g2i[rv].end());
      g2i[rv].clear();
    }

    weight[u] += abs(w);
    weight[v] += abs(w);
  }
  Type calc_weight(int u, int v) {
    if(i2g[u] != i2g[v]) return INF;
    return weight[v] - weight[u];
  }
};

int main() {
  int N, Q; cin >> N >> Q;

  QuickFind<long long int> qf(N);
  for(int i=0; i<Q; i++) {
    string query; cin >> query;

    if(query == "COMPARE") {
      int u, v; cin >> u >> v;
      u--; v--;
      long long int ans = qf.calc_weight(u, v);
      if(ans == INF) cout << "WARNING" << endl;
      else cout << ans << endl;
    }
    else {
      int u, v, w; cin >> u >> v >> w;
      u--; v--;
      qf.merge(u, v, w);
    }
  }
  return 0;
}
accuracy: 0.18181818181818182
time_ms: 160
memory_kb: 3224
final_rank: 20

code_snippet: #include <stdio.h>
#include <cmath>
#include <algorithm>
#include <cfloat>
#include <stack>
#include <queue>
#include <vector>
#include <string>
#include <iostream>
#include <set>
#include <map>
#include <time.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 100000

int boss[NUM],BASE[NUM],ADD[NUM];

int get_boss(int id){
	if(boss[id] == id)return id;
	else{

		int next_boss = get_boss(boss[id]);

		BASE[id] += BASE[boss[id]];

		return boss[id] =  next_boss;
	}
}

int get_value(int id){
	return BASE[id]+ADD[id]-ADD[boss[id]];
}

void unite(int A,int B,int diff){

	int boss_A = get_boss(A);
	int boss_B = get_boss(B);

	if(boss_A == boss_B)return;

	boss[boss_B] = boss_A;
	BASE[boss_B] += BASE[A]+ADD[A]+diff-(BASE[B]+ADD[B]);
}

int main(){

	int N,Q;
	scanf("%d %d",&N,&Q);

	for(int i = 0; i < N; i++){
		boss[i] = i;
		BASE[i] = 0;
		ADD[i] = 0;
	}

	char buf[8];

	int A,B,diff;

	for(int loop = 0; loop < Q; loop++){
		scanf("%s",buf);

		if(buf[0] == 'I'){

			scanf("%d %d %d",&A,&B,&diff);
			A--;
			B--;

			ADD[A] += diff;
			ADD[B] += diff;

			unite(A,B,diff);

		}else{ //compare
			scanf("%d %d",&A,&B);
			A--;
			B--;

			if(get_boss(A) != get_boss(B)){
				printf("WARNING\n");
				continue;
			}

			printf("%d\n",get_value(B)-get_value(A));
		}
	}

	return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 4372
final_rank: 1