某岛

… : "…アッカリ~ン . .. . " .. .
July 15, 2022

Codeforces Tinkoff Challenge – Elimination Round

G. Oleg and chess

先考虑网络流。。。是最朴素的二分图匹配。。。
还是设法要减少边的规模。。。我们类比扫描线来做矩形合并。。
从左到右扫描每一列,我们用函数式线段树,就能维护出代表这一列的线段树的根节点状态。。
那么只要从源点向根节点连过去一条容量为 1 的边即可。。注意需要保证这些线段树共享同一组闭合状态。。。

总感觉有更好的做法。。。

const int N = int(1e4) + 9;

int T[N], H[N]; VI adj[N];
int n, m;

namespace Chairman_Tree {
#define lx c[0][x]
#define rx c[1][x]
#define ly c[0][y]
#define ry c[1][y]
#define lz c[0][z]
#define rz c[1][z]
#define ml ((l+r)>>1)
#define mr (ml+1)
#define lc lx, l, ml
#define rc rx, mr, r
    const int NN = 100*N;
    int c[2][NN]; int tot;
    int pp; int dd;
    int new_node() {
        return ++tot;
    }
    int new_node(int y) {
        int x = ++tot; lx = ly; rx = ry;
        return x;
    }

    void Build(int& x, int l, int r) {
        if (l == r) {
            x = l;
        } else {
            x = new_node();
            Build(lc);
            Build(rc);
        }
    }

    int Insert(int x, int l, int r, int y, int a, int b) {
        if (b < l || r < a) return x;
        if (a <= l && r <= b) {
            return y;
        } else {
            x = new_node(x);
            lx = Insert(lc, ly, a, b);
            rx = Insert(rc, ry, a, b);
            return x;
        }
    }

} using namespace Chairman_Tree;

VII del[N], add[N];

int main(){

#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    //freopen("/Users/minakokojima/Documents/GitHub/ACM-Training/Workspace/out.txt", "w", stdout);
#endif

    RD(n); Rush {
        int x1, y1, x2, y2; RD(x1, y1, x2, y2); ++x2;
        add[x1].PB({y1, y2});
        del[x2].PB({y1, y2});
    }

    atcoder::mf_graph<int> G(NN);
    int s = 0, t = n+1; REP_1(i, n) G.add_edge(i, t, 1);
    tot = t;

    int x; Build(x, 1, n); int o = x, a = 0; REP_1(i, n) {
        int y = x;
        for (auto e: del[i]) x = Insert(x, 1, n, o, e.fi, e.se);
        for (auto e: add[i]) x = Insert(x, 1, n, 0, e.fi, e.se);
        if (x != y) {
            if (y && a) G.add_edge(s, y, a);
            a = 0;
        }
        ++a;
    }
    if (x) G.add_edge(s, x, a);

    FOR_1(x, t+1, tot) {
        if (lx) G.add_edge(x, lx, INF);
        if (rx) G.add_edge(x, rx, INF);
    }

    cout << G.flow(s, t) << endl;
}