---
# System prepended metadata

title: IOI2007 Day1-2 洪水 (Flood)
tags: [IOI]

---

---
tags: IOI
---
# IOI2007 Day1-2 洪水 (Flood)

定数倍高速化が本質(？)

## 問題文

https://www.ioi-jp.org/ioi/2007/problem/day1/flood-prob-j.pdf
https://oj.uz/problem/view/IOI07_flood

$N$ 個の点と $W$ 個の壁がある。
壁は点と点をつなぎ、座標軸と並行で、他の点をまたがない。
また、壁は他の壁と端点以外で共有点を持たない。$\Leftrightarrow$ 壁と壁の共有点は全て点になっている。
壁に囲まれていない外側の部分は水に浸かっている。
全領域が水に浸かるまで、以下が繰り返される。
- 片側のみ水に浸かっている壁が破壊される

最終的に残る壁を全て報告せよ。

$N ≤ 100000$

## 考察

とりあえずシミュレーションを考える。
適当な連結成分(？)について、必ず外側に入る点を見つけて、そこから外側を1周走査する。
同じ辺が2回出てきたらそれが答えで、出てきた辺は破壊 OR 水没だから消去する を繰り返していけば良い。
必ず外側に入る点を見つけるのがネックで、$O(N\log N + M)$ になる。
必ず外側に入る点は set<pair<int, int>> に入れて一番小さいのを選べば良い。

TLE 81点

81点なので定数倍が遅いことがわかる。
ネックの set<pair<int, int>> をあらかじめソートに変えると、10倍以上速くなって通る(？？？)

## 実装

115ms / 2000ms

https://oj.uz/submission/211954

```cpp
#include <bits/stdc++.h>
using namespace std;
using pii = pair<int, int>;
using tuplis = array<int, 3>;
#define rep(b) for(int i = 0; i < b; i++)
#define each(i,a) for(auto&& i : a)
#define all(a) begin(a), end(a)
 
 
struct wall{
    int to = -1, index;
    wall(){}
    wall(int to, int index): to(to), index(index){}
    bool exist() const { return to + 1; }
};
int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int n;
    cin >> n;
    vector<pii> p(n);
    each(i, p) cin >> i.first >> i.second;
    vector<array<wall, 4>> g(n);
    int w;
    cin >> w;
    rep(w){
        int a, b;
        cin >> a >> b;
        a--; b--;
        int d = 0;
        if(p[a].first < p[b].first) d = 0;
        else if(p[a].first > p[b].first) d = 2;
        else if(p[a].second < p[b].second) d = 1;
        else d = 3;
        g[a][d] = {b, i};
        g[b][d ^ 2] = {a, i};
    }
    vector<bool> ans(w, 1);
    vector<int> sorted(n);
    iota(all(sorted), 0);
    sort(all(sorted), [&](int a, int b){ return p[a] < p[b]; });
    int i = 0;
    while(true){
        while(i < n && all_of(all(g[sorted[i]]), [](const wall& w){ return !w.exist(); })) i++;
        if(i == n) break;
        int start = sorted[i], at = start, d = 0;
        vector<pii> visit;
        if(!g[at][d].exist()) d = 1;
        do{
            if(!g[at][d].exist()){
                d++;
                d &= 3;
                continue;
            }
            visit.emplace_back(at, d);
            ans[g[at][d].index] = !ans[g[at][d].index];
            at = g[at][d].to;
            d--;
            d &= 3;
        }while(at != start);
        each(i, visit){
            int at, d;
            tie(at, d) = i;
            if(!g[at][d].exist()) continue;
            int at2 = g[at][d].to, d2 = d ^ 2;
            g[at][d].to = -1;
            g[at2][d2].to = -1;
        }
    }
    cout << accumulate(ans.begin(), ans.end(), 0) << '\n';
    rep(w) if(ans[i]) cout << i + 1 << '\n';
}
```