#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<int> active;
for (auto &evt : events) {
if (!evt.is_remove) {
active.insert(A[evt.box_id] - 1);
continue;
}
// for (auto &el : active) {
// if (el+1 > A[evt.box_id] && el+1 < B[evt.box_id]) {
// dsu.unite(evt.box_id, events[el].box_id);
// }
// }
auto leftPoint = active.upper_bound(A[evt.box_id] - 1);
auto rightPoint = active.rbegin();
if (leftPoint != active.end())
dsu.unite(evt.box_id, events[*leftPoint].box_id);
if (events[*rightPoint].box_id != events[*leftPoint].box_id)
dsu.unite(evt.box_id, events[*rightPoint].box_id);
active.erase(A[evt.box_id] - 1);
}
// 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 time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |