結果
問題 | No.2295 Union Path Query (Medium) |
ユーザー |
|
提出日時 | 2023-02-12 04:12:49 |
言語 | C++14 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 118 ms / 4,000 ms |
コード長 | 4,186 bytes |
コンパイル時間 | 1,846 ms |
コンパイル使用メモリ | 172,380 KB |
実行使用メモリ | 5,760 KB |
最終ジャッジ日時 | 2024-11-22 13:41:53 |
合計ジャッジ時間 | 16,029 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge3 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | AC * 53 |
ソースコード
#include <bits/stdc++.h>using namespace std;using ll = long long;template<const unsigned int MOD> struct prime_modint {using mint = prime_modint;unsigned int v;prime_modint() : v(0) {}prime_modint(unsigned int a) { a %= MOD; v = a; }prime_modint(int a) { a %= (int)(MOD); if(a < 0)a += MOD; v = a; }prime_modint(long long a) { a %= (int)(MOD); if(a < 0)a += MOD; v = a; }static constexpr int mod() { return MOD; }mint& operator++() {v++; if(v == MOD)v = 0; return *this;}mint& operator--() {if(v == 0)v = MOD; v--; return *this;}mint operator++(int) { mint result = *this; ++*this; return result; }mint operator--(int) { mint result = *this; --*this; return result; }mint& operator+=(const mint& rhs) { v += rhs.v; if(v >= MOD) v -= MOD; return *this; }mint& operator-=(const mint& rhs) { if(v < rhs.v) v += MOD; v -= rhs.v; return *this; }mint& operator*=(const mint& rhs) {v = (unsigned int)((unsigned long long)(v) * rhs.v % MOD);return *this;}mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }mint operator+() const { return *this; }mint operator-() const { return mint() - *this; }mint pow(long long n) const {assert(0 <= n);mint r = 1, x = *this;while (n) {if (n & 1) r *= x;x *= x;n >>= 1;}return r;}mint inv() const { assert(v); return pow(MOD - 2); }friend mint operator+(const mint& lhs, const mint& rhs) { return mint(lhs) += rhs; }friend mint operator-(const mint& lhs, const mint& rhs) { return mint(lhs) -= rhs; }friend mint operator*(const mint& lhs, const mint& rhs) { return mint(lhs) *= rhs; }friend mint operator/(const mint& lhs, const mint& rhs) { return mint(lhs) /= rhs; }friend bool operator==(const mint& lhs, const mint& rhs) { return (lhs.v == rhs.v); }friend bool operator!=(const mint& lhs, const mint& rhs) { return (lhs.v != rhs.v); }friend std::ostream& operator << (std::ostream &os, const mint& rhs) noexcept { return os << rhs.v; }};//using mint = prime_modint<1000000007>;using mint = prime_modint<998244353>;int main(){ios::sync_with_stdio(false);cin.tie(0);int N, X, Q;cin >> N >> X >> Q;//ここからUnion Findvector<int> parent_or_size(N, -1);vector<int> weight(N, 1 << 30); //親への辺の重み,初期値は大きい値を入れておくvector<mint> ans(N); //連結成分内の頂点対の距離の総和auto leader = [&](int v){while(parent_or_size[v] >= 0) v = parent_or_size[v];return v;};//distanceは頂点u, 頂点v 間のmax距離を求める関数//頂点u, 頂点v から開始して親への辺の重みが小さい順に親を辿る//parent_or_size[u] が負の値のときに代表元を越えた判定になるので負の値になったら非連結auto distance = [&](int u, int v){int ans = 0;while(u != v){if (weight[u] > weight[v]) swap(u, v);ans = weight[u], u = parent_or_size[u];if(u < 0) return -1;}return ans;};//頂点u, 頂点v を重み w の辺でマージauto merge = [&](int u, int v, int w){int x = leader(u), y = leader(v);if(x == y) return;if(-parent_or_size[x] < -parent_or_size[y]) swap(x, y);ans[x] += ans[y] + mint(parent_or_size[x]) * parent_or_size[y] * w;parent_or_size[x] += parent_or_size[y];parent_or_size[y] = x;weight[y] = w; //親への辺の重みを w に更新};//ここまでUnion Findwhile(Q--){int type, u, v, w;cin >> type;if(type == 1){cin >> v >> w;merge(v, X, w);}else if(type == 2){cin >> u >> v;v = distance(u, v);cout << v << '\n';if(v != -1) (X += v) %= N;}else if(type == 3){cin >> v;cout << ans[leader(v)] << '\n';}else{cin >> v;(X += v) %= N;}}}