Submission #1211169

#TimeUsernameProblemLanguageResultExecution timeMemory
1211169madamadam3Port Facility (JOI17_port_facility)C++20
0 / 100
0 ms320 KiB
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

struct DSU {
    int n; vector<int> par, siz;
    vector<vector<int>> adj;

    DSU(int N) {
        n = N;
        par.resize(n);
        siz.assign(n, 1);
        adj.assign(n, vector<int>());

        iota(par.begin(), par.end(), 0);
    }

    int find(int v) {
        if (par[v] == v) return v;
        return par[v] = find(par[v]);
    }

    void unite(int a, int b) {
        int oa = a, ob = b;

        a = find(a);
        b = find(b);

        if (a != b) {
            if (siz[a] < siz[b]) swap(a, b);
            par[b] = a;
            siz[a] += siz[b];

            adj[oa].push_back(ob);
            adj[ob].push_back(oa);
        }
    }
};

struct Fenw {
    int n; vector<int> bit;

    Fenw(int N) {
        n = N;
        bit.assign(n, 0);
    }

    int g(int i) {
        return i & (i + 1);
    }

    int h(int j) {
        return j | (j+1);
    }

    void update(int idx, int delta) {
        while (idx < n) {
            bit[idx] += delta;
            idx = h(idx);
        }
    }

    int query(int r) {
        int res = 0;
        while (r >= 0) {
            res += bit[r];
            r = g(r) - 1;
        }

        return res;
    }

    int query(int l, int r) {
        return query(r) - query(l - 1);
    }
};

struct Event {
    int time, box_id;
    bool is_remove;

    const bool operator<(const Event &other) {
        return time < other.time;
    }
};

const int MAXN = 1'000'001;
const int MOD = 1'000'000'007;
int n;

int A[MAXN], B[MAXN];
vector<Event> events;

ll modexp(ll a, ll p) {
    if (p == 0) return 1;
    if (p == 1) return a;

    ll ans = modexp(a, p / 2);
    ans %= MOD;

    ans *= ans;
    ans %= MOD;

    if (p % 2 == 1) ans *= a;
    ans %= MOD;

    return ans % MOD;
}

void solve() {
    int ways = 1;
    
    vector<int> groups(n, -1);
    auto dsu = DSU(n);
    
    // step (1) create the final dsu structure merging all intersections
    set<pair<int, int>> active;
    for (auto &ev : events) {
        int id = ev.box_id;
        if (ev.is_remove) {
            active.erase({B[id], id});
        } else {            
            auto itL = active.upper_bound({A[id], -1});
            if (itL != active.end() && itL->first < B[id])
                dsu.unite(id, itL->second);     

            auto itR = active.lower_bound({B[id], -1});
            if (itR != active.begin()) {
                --itR;
                if (itR->first > A[id] && itR->first < B[id] && itR->second != itL->second)
                    dsu.unite(id, itR->second); 
            }

            active.insert({B[id], id});
        }
    }
    
    // step (2) make an initial colouring of the graph
    set<int> heads;
    for (int i = 0; i < n; i++) {
        heads.insert(dsu.find(i));
        if (groups[dsu.find(i)] != -1) continue;

        queue<int> q;
        q.push(dsu.find(i));
        groups[dsu.find(i)] = 1;

        while (!q.empty()) {
            int cur = q.front();
            q.pop();

            for (auto &v : dsu.adj[cur]) {
                if (groups[v] == -1) {
                    groups[v] = groups[cur] == 1 ? 2 : 1;
                    q.push(v);
                } else if (groups[v] == groups[cur]) {
                    cout << 0;
                    return;
                }
            }
        }
    }

    // step (3) re-add every edge, but check if the 2 nodes have the same colour, if they do exit
    Fenw white = Fenw(2*n+2), black = Fenw(2*n+2);
    for (auto &evt : events) {
        bool remove = evt.is_remove;
        int box = evt.box_id;

        if (!remove) {
            (groups[box] == 1 ? white : black).update(A[box], 1);
        } else {
            (groups[box] == 1 ? white : black).update(B[box], -1);
            int diff = (groups[box] == 1 ? white : black).query(A[box], B[box]);
            if (diff != 0) {
                cout << 0;
                return;
            }
        }
    }

    int cmps = heads.size();
    ways = modexp(2, cmps); // either group 1 in A g2 B or g1 B g2 A so 2 ways for each cmp
    cout << ways;
}

void brute() {
    int ways = 1;
    vector<vector<int>> crossings(n, vector<int>()); // had this idea previously to precompute crossings js was trying to brute force first

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            int ci = i, cj = j;
            if (A[cj] < A[ci]) swap(ci, cj);
            if (!(A[ci] < A[cj] && A[cj] < B[ci] && B[ci] < B[cj])) continue;

            crossings[ci].push_back(cj);
            crossings[cj].push_back(ci);
        }
    }
    
    vector<int> group(n, -1);
    int cmps = 0;
    
    // push the constraints down the group (ie. each incompatible thing on a different side)
    for (int i = 0; i < n; i++) {
        if (group[i] != -1) continue;
        group[i] = 1;
        cmps++;

        queue<int> q;
        q.push(i);

        while (!q.empty()) {
            int cur = q.front();
            q.pop();

            for (auto &restriction : crossings[cur]) {
                if (group[restriction] == -1) {
                    group[restriction] = group[cur] == 1 ? 2 : 1; // push down the constraint
                    q.push(restriction);
                } else if (group[restriction] == group[cur]) { // inconsistency, need to break
                    cout << 0;
                    return;
                }
            }
        }

    }

    ways = modexp(2, cmps); // either group 1 in A g2 B or g1 B g2 A so 2 ways for each cmp
    cout << ways;
}

signed main() {
    cin.tie(0)->sync_with_stdio(0);
    
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> A[i] >> B[i];
    }

    for (int i = 0; i < n; i++) {
        events.push_back(Event {A[i], i, false});
        events.push_back(Event {B[i], i, true});
    }

    sort(events.begin(), events.end());

    solve();
    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...