--- tags: IOI --- # IOI2008 Day2-2 転送機 (Teleporters) ## 問題文 https://www.ioi-jp.org/ioi/2008/problems/Day2_jpn/teleporters_j.pdf https://oj.uz/problem/view/IOI08_teleporters 数直線上にテレポーターが $N$ 個あり、位置 $W_i$ と位置 $E_i$ を双方向につないでいます。 あなたは数直線上を正の方向に進み、テレポーターを通るたびにそのテレポーターを使います。 好きな位置に $M$ 個テレポーターを追加するとき、テレポーターを使う回数は最大で何回になるでしょうか? $N, M ≤ 10^6$ ## 考察 初期状態で通らないルートは入ることも出ることもないのでループになっている。 テレポーターを最後からループの中に入れるように作ると、そのループが通るルートに追加される。 1つのテレポーターの追加につき2つ以上のループを追加することはどうやってもできないから、長いループから貪欲にテレポーターの追加すると良い。 余ったテレポーターは、偶数個のときは2個ずつで使い切れるが、奇数個では使いきれそうにないので、1個は片側だけ使う。 ## 実装 975 ms / 1000 ms https://oj.uz/submission/218281 FastIO で 748 ms なのでやっぱり cin は重い 座標圧縮をしなければもうちょっと速そう ```cpp #include <bits/stdc++.h> using namespace std; using pii = pair<int, int>; #define rep(a) for(int i = 0; i < a; i++) #define each(i,a) for(auto&& i : a) #define all(a) begin(a), end(a) int main(){ cin.tie(nullptr); ios::sync_with_stdio(false); int n, m; cin >> n >> m; vector<pii> a(n); vector<int> x; each(i, a){ int a, b; cin >> a >> b; i = {a, b}; x.push_back(a); x.push_back(b); } sort(all(x)); x.erase(unique(all(x)), x.end()); vector<int> to(n * 2); each(i, a){ i.first = lower_bound(all(x), i.first) - x.begin(); i.second = lower_bound(all(x), i.second) - x.begin(); to[i.first] = i.second; to[i.second] = i.first; } vector<int> color(n * 2, -1), cnt; int at = 0, c = 0, ans = 0; while(at != n * 2){ color[at] = c; ans++; at = to[at] + 1; } rep(n * 2) if(color[i] == -1){ cnt.push_back(0); int at = i; c++; while(at != n * 2 && color[at] == -1){ color[at] = c; cnt.back()++; at = to[at] + 1; } } sort(all(cnt)); while(cnt.size() && m){ ans += cnt.back() + 2; cnt.pop_back(); m--; } ans += m * 2 - m % 2; cout << ans << endl; } ```