제출 #1343977

#제출 시각아이디문제언어결과실행 시간메모리
1343977biank절취선 (JOI14_ho_t5)C++20
100 / 100
257 ms13236 KiB
#include <bits/stdc++.h>
 
using namespace std;
 
#define forsn(i, s, n) for (int i = int(s); i < int(n); i++)
#define forn(i, n) forsn(i, 0, n)
#define dforsn(i, s, n) for (int i = int(n) - 1; i >= int(s); i--)
#define dforn(i, n) dforsn(i, 0, n)
#define qforn(i, n) for (i = 0; i < n; i++)
 
using vi = vector<int>;
using ii = pair<int, int>;
using vii = vector<ii>;
using ll = long long;
using ld = long double;
using vll = vector<ll>;
using vb = vector<bool>;
using pll = pair<ll, ll>;

#define sz(x) int(x.size())
#define all(x) begin(x), end(x)

#define pb push_back
#define eb emplace_back

#define fst first
#define snd second

const int ADD = 1;
const int ERASE = 3;
const int QUERY = 2;

struct FTree {
    int n;
    vll ft;
    FTree(int _n) : n(_n + 9), ft(n, 0) {}
    void update(int p, ll v) {
        for (++p; p < n; p += p & -p) ft[p] += v;
    }
    ll get(int p) {
        ll s = 0;
        for (; p > 0; p -= p & -p) s += ft[p];
        return s;
    }
};

struct DSU {
    vi p;
    int c;
    DSU(int n = 0) : p(n, -1), c(n) {}
    int find(int x) {
        if (p[x] < 0) return x;
        return p[x] = find(p[x]);
    }
    void unite(int x, int y) {
        x = find(x), y = find(y);
        if (x == y) return;
        if (p[x] > p[y]) swap(x, y);
        p[x] += p[y], p[y] = x, c--;
    }
};

using Event = tuple<int, int, int, int, int>;

struct Node;

DSU dsu;

using NodePtr = Node*;

struct Node {
    int x;
    int u;
    int lazy;
    int priority;
    NodePtr left, right;
    Node(int val, int id) {
        x = val;
        u = id;
        lazy = -1;
        priority = rand();
        left = right = nullptr;
    }
    void addLazy(int id) {
        if (lazy == -1) lazy = id;
        dsu.unite(lazy, id);
        lazy = id;
    }
    void applyLazy() {
        if (lazy == -1) return;
        if (left != nullptr) left->addLazy(lazy);
        if (right != nullptr) right->addLazy(lazy);
        dsu.unite(u, lazy);
        lazy = -1;
    }
};

pair<NodePtr, NodePtr> split(NodePtr u, int k) {
    if (u == nullptr) return make_pair(nullptr, nullptr);
    u->applyLazy();
    if (u->x < k) {
        auto [left, right] = split(u->right, k);
        u->right = left;
        return make_pair(u, right);
    } else {
        auto [left, right] = split(u->left, k);
        u->left = right;
        return make_pair(left, u);
    }
}

NodePtr merge(NodePtr left, NodePtr right) {
    if (right == nullptr) return left;
    if (left == nullptr) return right;
    if (left->priority > right->priority) {
        left->applyLazy();
        left->right = merge(left->right, right);
        return left;
    } else {
        right->applyLazy();
        right->left = merge(left, right->left);
        return right;
    }
}

NodePtr insert(NodePtr root, int x, int i) {
    auto [left, right] = split(root, x);
    return merge(merge(left, new Node(x, i)), right);
}

NodePtr erase(NodePtr root, int x) {
    auto [left, aux] = split(root, x);
    auto [middle, right] = split(aux, x + 1);
    middle->applyLazy();
    return merge(left, right);
}

NodePtr update(NodePtr root, int x1, int x2, int idx) {
    auto [left, aux] = split(root, x1);
    auto [middle, right] = split(aux, x2 + 1);
    if (middle != nullptr) middle->addLazy(idx);
    return merge(merge(left, middle), right);
}

void dfs(NodePtr root) {
    if (root == nullptr) return;
    root->applyLazy();
    dfs(root->left);
    dfs(root->right);
}

int main() {
    ios::sync_with_stdio(0);                
    cin.tie(0); cout.tie(0);
    
    int w, h, n;
    cin >> w >> h >> n;
    
    vector<tuple<int, int, int, int>> v = {
        {0, 0, w, 0},
        {w, 0, w, h},
        {w, h, 0, h},
        {0, h, 0, 0}
    };
    
    forn(i, n) {
        int a, b, c, d;
        cin >> a >> b >> c >> d;
        v.eb(a, b, c, d);
    }
    
    vector<Event> events;
    vii pos;
    for (int i = 0; auto [a, b, c, d] : v) {
        pos.eb(b, i), pos.eb(d, i);
        if (a == c) {
            if (b > d) swap(b, d);
            events.eb(a, QUERY, b, d, i);
        } else {
            if (a > c) swap(a, c); 
            assert(b == d);
            events.eb(a, ADD, b, d, i);
            events.eb(c, ERASE, b, d, i);
        }
        i++;
    }
    sort(all(events));
    
    sort(all(pos));
    pos.erase(unique(all(pos)), end(pos));
    
    ll ret = -sz(v);
    dsu = DSU(sz(v));
    NodePtr root = nullptr;
    int cnt = 0;
    for (FTree ft(sz(pos)); auto [_, t, x1, x2, i] : events) {
        if (t == ADD) {
            x1 = int(lower_bound(all(pos), make_pair(x1, i)) - begin(pos));
            ft.update(x1, +1);
            root = insert(root, x1, i);
        } else if (t == ERASE) {
            x1 = int(lower_bound(all(pos), make_pair(x1, i)) - begin(pos));
            ft.update(x1, -1);
            root = erase(root, x1);
        } else {
            x1 = int(lower_bound(all(pos), make_pair(x1, 0)) - begin(pos));
            x2 = int(lower_bound(all(pos), make_pair(x2 + 1, 0)) - begin(pos) - 1);
            root = update(root, x1, x2, i);
            ll curr = ft.get(x2 + 1) - ft.get(x1);
            ret += curr;
        }
    }
    
    dfs(root);
    
    int C = dsu.c;
    
    cout << ret + C << "\n";
    
    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...