#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#include #pragma warning(disable:4996) typedef long long ll; typedef unsigned long long ull; #define MIN(a, b) ((a)>(b)? (b): (a)) #define MAX(a, b) ((a)<(b)? (b): (a)) #define LINF 9223300000000000000 #define LINF2 1223300000000000000 #define INF 2140000000 //const long long MOD = 1000000007; const long long MOD = 998244353; using namespace std; class UF { private: int num; vector par; vector siz; public: //vector val; public: UF(int n): num(n) { par.resize(n); siz.resize(n); //val.resize(n); int i; for(i=0; i > g; vector eu, bf, af; void dfs(int par, int curr) { int cnt0=(int)eu.size(); eu.push_back(curr); bf[curr] = cnt0; int i; for (i = 0; i < (int)g[curr].size(); i++) { int next = g[curr][i]; if (par == next) continue; dfs(curr, next); } af[curr] = (int)eu.size(); return; } const long long INF2 = (((ll)1<<31)-1); template class SegTree // 0-indexed { private: int n; // 葉の数 vector data; // ノードの値を持つ配列 vector lazy; // 遅延評価を持つ配列 T def; // 初期値かつ単位元 T operation(T a, T b) // 区間クエリで使う処理 { //return min(a, b); // 区間minクエリ return a+b; // 区間和クエリ } T update(T a, T b) // 点更新で使う処理 { //return a+b; // 加算の場合 return b; // 更新の場合 } void eval( int k, int l, int r ) // ノードkについて遅延評価を行う { if(lazy[k] != 0) { data[k] += lazy[k]; if(r - l > 1) { lazy[2*k+1] += lazy[k] / 2; lazy[2*k+2] += lazy[k] / 2; } lazy[k] = 0; } return; } void _add(int a, int b, T x, int k, int l, int r) { if(r < 0) r = n; eval(k, l, r); // k 番目のノードに対して遅延評価を行う if(b <= l || r <= a) return; // 範囲外なら何もしない // 完全に被覆しているならば、遅延配列に値を入れた後に評価 if(a <= l && r <= b) { lazy[k] += (r - l) * x; eval(k, l, r); } // そうでないならば、子ノードの値を再帰的に計算して、 // 計算済みの値をもらってくる else { _add(a, b, x, 2*k+1, l, (l+r)/2); _add(a, b, x, 2*k+2, (l+r)/2, r); data[k] = data[2*k+1] + data[2*k+2]; } } // 区間[a,b)の総和。ノードk=[l,r)に着目している。 T _query(int a, int b, int k, int l, int r) { if (r <= a || b <= l) return def; // 交差しない eval(k, l, r); if (a <= l && r <= b) return data[k]; // a,l,r,bの順で完全に含まれる else { T c1 = _query(a, b, 2 * k + 1, l, (l + r) / 2); // 左の子 T c2 = _query(a, b, 2 * k + 2, (l + r) / 2, r); // 右の子 return operation(c1, c2); } } public: SegTree(int _n) { // _n:必要サイズ //def = INF2; // 初期値かつ単位元(minのときINF2) def = 0; // 初期値かつ単位元(和のとき0) n = 1; while (n < _n) n *= 2; data = vector(2 * n - 1, def); lazy = vector(2 * n - 1, 0); } // 場所i(0-indexed)の値をxで更新 void change(int i, T x) { i += n - 1; data[i] = update(data[i], x); while (i > 0) { i = (i - 1) / 2; data[i] = operation(data[i * 2 + 1], data[i * 2 + 2]); } } // 区間更新 void add(int a, int b, T x) { return _add(a, b, x, 0, 0, n); } // [a, b)の区間クエリを実行 T query(int a, int b) { return _query(a, b, 0, 0, n); } // 添字でアクセス T operator[](int i) { return data[i + n - 1]; } }; void solve() { int n, Q; scanf("%d%d", &n, &Q); vector t(Q), a(Q), b(Q); int cnt = 0; int i; for (i = 0; i < Q; i++) { scanf("%d%d%d", &t[i], &a[i], &b[i]); a[i]--; if(t[i]==1) b[i]--; if (t[i] == 1) { cnt++; } } int num = cnt; vector mp(n+num); for (i = 0; i < n + num; i++) mp[i] = i; UF uf(n + num); g.resize(n + num); bf.resize(n + num); af.resize(n + num); cnt = 0; for (i = 0; i < Q; i++) { if (t[i] == 1) { int aa = mp[uf.find(a[i])]; int bb = mp[uf.find(b[i])]; int id = n + cnt; g[id].push_back(aa); g[aa].push_back(id); g[id].push_back(bb); g[bb].push_back(id); if (uf.same(aa, bb)) { cnt++; continue; } uf.unite(aa, bb); uf.unite(aa, id); int p = uf.find(aa); mp[p] = id; cnt++; } } set ss; for (i = 0; i < n; i++) { ss.insert(mp[uf.find(i)]); } auto it0 = ss.begin(); for (; it0 != ss.end(); ++it0) { dfs(-1, *it0); } SegTree S(n + num); UF uf2(n + num); for (i = 0; i < n + num; i++) mp[i] = i; cnt = 0; for (i = 0; i < Q; i++) { if (t[i] == 1) { int aa = mp[uf2.find(a[i])]; int bb = mp[uf2.find(b[i])]; int id = n + cnt; if (uf2.same(aa, bb)) { cnt++; continue; } uf2.unite(aa, bb); uf2.unite(aa, id); int p = uf2.find(aa); mp[p] = id; cnt++; } else if (t[i] == 2) { int aa = mp[uf2.find(a[i])]; int t0 = bf[aa], t1 = af[aa]; S.add(t0, t1, b[i]); } else { int aa = bf[a[i]]; ll ans=S.query(aa, aa+1); printf("%lld\n", ans); } } return; } int main(int argc, char* argv[]) { #if 1 solve(); #else int T; scanf("%d", &T); int t; for(t=0; t