結果

問題 No.3617 Swap
コンテスト
ユーザー kwm_t
提出日時 2026-08-10 02:48:36
言語 C++23
(gcc 15.2.0 + boost 1.90.0)
コンパイル:
g++-15 -O2 -lm -std=c++23 -Wuninitialized -DONLINE_JUDGE -o a.out _filename_
実行:
./a.out
結果
AC  
実行時間 383 ms / 2,000 ms
+ 209µs
コード長 5,385 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 2,168 ms
コンパイル使用メモリ 349,808 KB
実行使用メモリ 42,240 KB
最終ジャッジ日時 2026-08-10 02:48:53
合計ジャッジ時間 14,449 ms
ジャッジサーバーID
(参考情報)
judge2_0 / judge1_0
このコードへのチャレンジ
(要ログイン)
サブタスク 配点 結果
サンプル 0 % AC * 4
小課題1 5 % AC * 3
小課題2 5 % AC * 5
小課題3 15 % AC * 14
小課題4 20 % AC * 21
小課題5 25 % AC * 8
小課題6 10 % AC * 8
小課題7 20 % AC * 56
合計 3 * 100% = 300 点
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

#include <bits/stdc++.h>
//#include <atcoder/all>
using namespace std;
// using namespace atcoder;
// using mint = modint1000000007;
// const int mod = 1000000007;
// using mint = modint998244353;
// const int mod = 998244353;
// const int INF = 1e9;
const long long LINF = 1e18;
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define rep2(i, l, r) for (int i = (l); i < (r); ++i)
#define rrep(i, n) for (int i = (n)-1; i >= 0; --i)
#define rrep2(i, l, r) for (int i = (r)-1; i >= (l); --i)
#define all(x) (x).begin(), (x).end()
#define allR(x) (x).rbegin(), (x).rend()
#define P pair<int, int>
template<typename A, typename B> inline bool chmax(A& a, const B& b) { if (a < b) { a = b; return true; } return false; }
template<typename A, typename B> inline bool chmin(A& a, const B& b) { if (a > b) { a = b; return true; } return false; }
#ifndef KWM_T_ALGORITHM_SEARCH_DOUBLING_HPP
#define KWM_T_ALGORITHM_SEARCH_DOUBLING_HPP

#include <vector>
#include <functional>
#include <utility>

namespace kwm_t::algorithm::search {
/**
 * @brief Doubling (Binary Lifting)
 *
 * 関数 f の k 回適用 f^k(x) を高速に求めるデータ構造。
 * nxt[v] = f(v) としたとき、
 * 2^i 回遷移した先を前計算することで O(log k) で遷移可能。
 *
 * value を持たせることで、遷移に伴う値(距離・重み・xor など)の
 * 累積も同時に計算できる。
 *
 * 典型用途:
 *   ・Functional Graph の k step
 *   ・テレポート問題
 *   ・祖先ジャンプ
 *   ・遷移コストの累積
 *
 * 計算量:
 *   構築 O(N log K)
 *   jump / jump_value / first_true : O(log K)
 *
 * @tparam T      遷移に付随する値の型
 * @tparam Merge  値をマージする関数 (例: std::plus)
 *
 * @param nxt     nxt[v] = v から1回遷移した先
 * @param value   各遷移に対応する値
 * @param log     最大ステップ数のビット長
 *
 * 制約 / 注意:
 *   ・first_true は単調性が必要
 *       f(jump(v,k)) が
 *       false false ... false true true ...
 *       の形になる必要がある
 *
 * 使用例:
 *   vector<int> nxt = {...};
 *   Doubling<> db(nxt);
 *   int v = db.jump(0, 1e18);
 *
 *   vector<long long> cost = {...};
 *   auto merge = [](auto a, auto b) { return a + b; };
 *   Doubling<long long, decltype(merge)> db2(nxt, cost, merge);
 *   auto [to, sum] = db2.jump_value(0, k);
 *
 * verified:
 *   https://atcoder.jp/contests/awc0025/submissions/74048140
 *   https://atcoder.jp/contests/abc438/submissions/74048565
 *   first_true
 *   https://atcoder.jp/contests/arc218/submissions/75493507
 */
struct DoublingNoValue {};
template<class T = DoublingNoValue, class Merge = std::plus<T>>
class Doubling {
public:
	int N;
	int LOG;

	Doubling(const std::vector<int>& nxt, int log = 60) : N((int)nxt.size()), LOG(log)
	{
		init(nxt);
	}

	Doubling(const std::vector<int>& nxt,
		const std::vector<T>& value,
		Merge m = Merge(),
		int log = 60)
		: N((int)nxt.size()), LOG(log), merge(m)
	{
		init(nxt, value);
	}

	// k回遷移
	int jump(int v, long long k) const {
		for (int i = 0; i < LOG; ++i) {
			if (k >> i & 1) v = to[i][v];
		}
		return v;
	}

	// value付き k回遷移
	std::pair<int, T> jump_value(int v, long long k) const {
		T res{};
		for (int i = 0; i < LOG; ++i) {
			if (k >> i & 1) {
				res = merge(res, val[i][v]);
				v = to[i][v];
			}
		}
		return { v, res };
	}

	// f(jump(v,k)) が true になる最小 k (存在しなければ -1)
	template<class F>
	long long first_true(int v, long long limit, F f) const {
		T acc{};
		if (f(v, acc)) return 0;

		long long k = 0;

		for (int i = LOG - 1; i >= 0; --i) {
			if (k + (1LL << i) > limit) continue;

			int nv = to[i][v];
			T nacc;
			if constexpr (std::is_same_v<T, DoublingNoValue>) nacc = acc;
			else nacc = merge(acc, val[i][v]);

			if (!f(nv, nacc)) {
				v = nv;
				acc = nacc;
				k += 1LL << i;
			}
		}

		if (k == limit) return -1;
		return k + 1;
	}

private:

	std::vector<std::vector<int>> to;
	std::vector<std::vector<T>> val;
	Merge merge;

	void init(const std::vector<int>& nxt) {
		to.assign(LOG, std::vector<int>(N));
		to[0] = nxt;

		for (int i = 1; i < LOG; ++i) {
			for (int v = 0; v < N; ++v) {
				to[i][v] = to[i - 1][to[i - 1][v]];
			}
		}
	}

	void init(const std::vector<int>& nxt, const std::vector<T>& value) {
		to.assign(LOG, std::vector<int>(N));
		val.assign(LOG, std::vector<T>(N));

		to[0] = nxt;
		val[0] = value;

		for (int i = 1; i < LOG; ++i) {
			for (int v = 0; v < N; ++v) {
				int u = to[i - 1][v];
				to[i][v] = to[i - 1][u];
				val[i][v] = merge(val[i - 1][v], val[i - 1][u]);
			}
		}
	}
};
} // namespace kwm_t::algorithm::search

#endif // KWM_T_ALGORITHM_SEARCH_DOUBLING_HPP
int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	int n, m, q; cin >> n >> m >> q;
	vector<int>l(m), r(m);
	rep(i, m) {
		cin >> l[i] >> r[i];
		l[i]--, r[i]--;
	}
	vector<long long>t(q), x(q);
	vector sh(m, vector<pair<long long, long long>>());
	// t kai ato no a[x]
	rep(i, q) {
		cin >> t[i] >> x[i];
		x[i]--;
		sh[t[i] % m].emplace_back(x[i], i);
		t[i] /= m;
	}
	vector<int>a(n);
	rep(i, n)a[i] = i;
	rep(i, m) {
		for (auto [xx, idx] : sh[i]) {
			x[idx] = a[xx];
		}
		swap(a[l[i]], a[r[i]]);
	}
	kwm_t::algorithm::search::Doubling db(a);
	rep(i, q) {
		auto ans = db.jump(x[i], t[i]);
		cout << ans + 1 << endl;
	}
	return 0;
}
0