#include <bits/stdc++.h>
using namespace std;
const int maxN = 1e5 + 10;
struct Qr {
int num, type, L, R;
bool operator < (const Qr& rhs) const {
if (num != rhs.num) return num < rhs.num;
return type < rhs.type;
}
} query[3 * maxN];
namespace DSU {
int par[maxN], sz[maxN], num_tplt, ON[maxN];
void init(int n) {
num_tplt = n;
for (int i = 1; i <= n; i++) {
par[i] = i;
sz[i] = 1;
}
}
int find_set(int u) {
return (par[u] == u) ? u : par[u] = find_set(par[u]);
}
void union_set(int u, int v) {
u = find_set(u);
v = find_set(v);
if (u == v) return ;
num_tplt--;
if (sz[u] < sz[v]) swap(u, v);
par[v] = u;
sz[u] += sz[v];
}
}
namespace sum{
int BIT[maxN];
void update(int pos, int val, int n) {
int p = pos;
while (p <= n) {
BIT[p] += val;
p += p & (-p);
}
}
int getSum(int pos) {
int p = pos, ans = 0;
while (p) {
ans += BIT[p];
p -= p & (-p);
}
return ans;
}
int getRange(int L, int R) {
if (L > R) return 0;
return getSum(R) - getSum(L - 1);
}
}
vector<int> posX, posY;
int A[maxN], B[maxN], C[maxN], D[maxN];
map<pair<int, int>, int> belong_to;
set<pair<int, int>> save;
int main() {
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int W, H, n;
cin >> W >> H >> n;
posX.push_back(0); posX.push_back(W);
posY.push_back(0); posY.push_back(H);
for (int i = 1; i <= n; i++) {
cin >> A[i] >> B[i] >> C[i] >> D[i];
posX.push_back(A[i]); posX.push_back(C[i]);
posY.push_back(B[i]); posY.push_back(D[i]);
}
//cout << '\n';
sort(posX.begin(), posX.end());
posX.erase(unique(posX.begin(), posX.end()), posX.end());
sort(posY.begin(), posY.end());
posY.erase(unique(posY.begin(), posY.end()), posY.end());
//for (auto v: posX) cout << v << ' '; cout << '\n';
//for (auto v: posY) cout << v << ' '; cout << '\n';
A[n + 1] = 0; B[n + 1] = 0; C[n + 1] = 0; D[n + 1] = H;
A[n + 2] = 0; B[n + 2] = H; C[n + 2] = W; D[n + 2] = H;
A[n + 3] = W; B[n + 3] = 0; C[n + 3] = W; D[n + 3] = H;
A[n + 4] = 0; B[n + 4] = 0; C[n + 4] = W; D[n + 4] = 0;
n += 4; int M = posY.size();
int Q = 0;
for (int i = 1; i <= n; i++) {
A[i] = lower_bound(posX.begin(), posX.end(), A[i]) - posX.begin() + 1;
C[i] = lower_bound(posX.begin(), posX.end(), C[i]) - posX.begin() + 1;
B[i] = lower_bound(posY.begin(), posY.end(), B[i]) - posY.begin() + 1;
D[i] = lower_bound(posY.begin(), posY.end(), D[i]) - posY.begin() + 1;
//cout << "line " << A[i] << ' ' << B[i] << ' ' << C[i] << ' ' << D[i] << '\n';
if (A[i] == C[i]) query[++Q] = {A[i], i, B[i], D[i]};
else {
query[++Q] = {A[i], 0, B[i], i};
query[++Q] = {C[i], 1000000, B[i], i};
}
}
DSU::init(n);
sort(query + 1, query + Q + 1);
long long ans = 0;
for (int i = 1; i <= Q; i++) {
auto [num, type, L, R] = query[i];
//cout << num << ' ' << type << ' ' << L << ' ' << R << ' ' << "idx = " << ((type > 0) ? type : R) << '\n';
if (type == 0) { /// Add a line
int idx = R, pos = L;
sum::update(pos, 1, M);
auto it = save.upper_bound({pos, 1e9});
if (it != save.begin()) {
it--;
auto [lt, rt] = *it; int org = belong_to[{lt, rt}];
if (lt <= pos && pos <= rt) {
save.erase(it);
if (sum::getRange(lt, pos - 1)) {
belong_to[{lt, pos - 1}] = org;
save.insert({lt, pos - 1});
}
if (sum::getRange(pos + 1, rt)) {
belong_to[{pos + 1, rt}] = org;
save.insert({pos + 1, rt});
}
}
}
save.insert({pos, pos});
belong_to[{pos, pos}] = idx;
}
else if (type == 1000000) { /// Remove a line
int idx = R, pos = L;
sum::update(pos, -1, M);
auto it = save.upper_bound({pos, 1e9});
if (it != save.begin()) {
it--;
auto [lt, rt] = *it;
if (lt <= pos && pos <= rt)
if (!sum::getRange(lt, rt))
save.erase(it);
}
}
else { /// Query A Range
int bonus = sum::getRange(L, R); /// Number of line between L and R
if (bonus) {
ans += bonus;
pair<int, int> asking = {R, 1e9};
auto it = save.upper_bound(asking); /// DSU section
int low = 2e9, high = -1;
while (it != save.begin()) {
it--; pair<int, int> X = *it;
if (X.second < L) break;
if (sum::getRange(max(L, X.first), min(R, X.second))) {
save.erase(it);
low = min(low, X.first);
high = max(high, X.second);
DSU::union_set(belong_to[X], type);
}
else asking = X;
if (save.size() == 0) break;
it = save.lower_bound(asking);
}
if (high != -1) {
save.insert({low, high});
belong_to[{low, high}] = DSU::find_set(type);
}
}
}
//cout << DSU::num_tplt << '\n';
//for (int i = 1; i <= n; i++)
//cout << DSU::find_set(i) << ' ';
//cout << '\n';
//for (auto it = save.begin(); it != save.end(); it++) {
//pair<int, int> X = *it;
//cout << "( " << X.first << ' ' << X.second << " )\n";
//}
//cout << '\n';
}
//cout << ans << '\n';
cout << ans + DSU::num_tplt - n;
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... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |