Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <bits/stdc++.h> // Удобный вызов всех библиотек
- using namespace std;
- using ll = long long; // Alias
- // Каждый лист соответствует интервалу [comp[i], comp[i+1]) с весом = comp[i+1] - comp[i].
- // Операция обновления (на интервале) заключается в том, что для каждого элемента,
- // если его значение меньше B, то оно устанавливается в B, а прирост (B - старое_значение)
- // умножается на вес интервала и суммируется.
- struct SegmentTree {
- int n; // количество листов (n = comp.size() - 1)
- vector<int> comp; // сжатые координаты (отсортированы и уникальны)
- vector<int> lazy; // "ленивые" обновления; -1 означает отсутствие обновления
- vector<int> mn, mx; // минимальное и максимальное значение в сегменте
- vector<ll> sum; // взвешенная сумма значений в сегменте
- vector<ll> weight; // суммарный вес сегмента
- SegmentTree(const vector<int>& comp_) : comp(comp_) {
- n = comp.size() - 1; // число интервалов
- lazy.assign(4 * n, -1);
- mn.assign(4 * n, 0);
- mx.assign(4 * n, 0);
- sum.assign(4 * n, 0);
- weight.assign(4 * n, 0);
- build(1, 0, n - 1);
- }
- // Построение дерева для узла idx, отвечающего за интервал [l, r]
- void build(int idx, int l, int r) {
- if(l == r) {
- weight[idx] = (ll)comp[l + 1] - comp[l];
- mn[idx] = 0;
- mx[idx] = 0;
- sum[idx] = 0;
- lazy[idx] = 0; // начальное значение 0
- } else {
- int mid = (l + r) / 2;
- build(idx * 2, l, mid);
- build(idx * 2 + 1, mid + 1, r);
- weight[idx] = weight[idx * 2] + weight[idx * 2 + 1];
- mn[idx] = min(mn[idx * 2], mn[idx * 2 + 1]);
- mx[idx] = max(mx[idx * 2], mx[idx * 2 + 1]);
- sum[idx] = sum[idx * 2] + sum[idx * 2 + 1];
- lazy[idx] = -1;
- }
- }
- // Применяет присваивание для узла idx: устанавливает все элементы в узле равными val.
- void apply(int idx, int val) {
- sum[idx] = (ll)val * weight[idx];
- mn[idx] = val;
- mx[idx] = val;
- lazy[idx] = val;
- }
- // Отталкивание ленивого обновления вниз (pushDown)
- void pushDown(int idx) {
- if(lazy[idx] != -1) {
- apply(idx * 2, lazy[idx]);
- apply(idx * 2 + 1, lazy[idx]);
- lazy[idx] = -1;
- }
- }
- // Функция update_range обновляет сегмент [ql, qr] (индексы листьев) так, что
- // для каждого элемента, если его значение меньше B, оно становится равным B.
- // При этом общий прирост добавляется в переменную added.
- void update_range(int idx, int l, int r, int ql, int qr, int B, ll &added) {
- if(ql > r || qr < l) return;
- if(ql <= l && r <= qr) {
- // Если максимальное значение в сегменте меньше B, обновляем весь сегмент разом
- if(mx[idx] < B) {
- ll newSum = (ll)B * weight[idx];
- added += newSum - sum[idx];
- apply(idx, B);
- return;
- }
- // Если минимальное значение в сегменте уже не меньше B, обновление не требуется
- if(mn[idx] >= B) {
- return;
- }
- }
- int mid = (l + r) / 2;
- pushDown(idx);
- update_range(idx * 2, l, mid, ql, qr, B, added);
- update_range(idx * 2 + 1, mid + 1, r, ql, qr, B, added);
- sum[idx] = sum[idx * 2] + sum[idx * 2 + 1];
- mn[idx] = min(mn[idx * 2], mn[idx * 2 + 1]);
- mx[idx] = max(mx[idx * 2], mx[idx * 2 + 1]);
- }
- // Функция обновления: обновляет сегмент [ql, qr]
- // и возвращает общий прирост.
- ll update(int ql, int qr, int B) {
- ll added = 0;
- if(ql > qr) return 0;
- update_range(1, 0, n - 1, ql, qr, B, added);
- return added;
- }
- };
- // Структура PaintLine поддерживает префиксное обновление для одного квадрата.
- // Для данного квадрата строится сегментное дерево по "сжатой" оси x.
- struct PaintLine {
- vector<int> comp; // сжатые x-координаты
- SegmentTree seg;
- PaintLine(const vector<int>& comp_) : comp(comp_), seg(comp_) {}
- // Функция updatePrefix обновляет префикс [0, A) значением B.
- ll updatePrefix(int A, int B) {
- int pos = int(lower_bound(comp.begin(), comp.end(), A) - comp.begin());
- if(pos <= 0) return 0;
- return seg.update(0, pos - 1, B);
- }
- };
- // Структура Snapshot описывает "снимок" с четырьмя координатами.
- // В оригинальной системе координат снимок покрывает прямоугольник с противоположными углами (x1, y1) и (x2, y2).
- struct Snapshot {
- int x1, y1, x2, y2;
- };
- int main(){
- ios::sync_with_stdio(false);
- cin.tie(nullptr);
- int n;
- cin >> n;
- vector<Snapshot> snaps(n);
- for (int i = 0; i < n; i++){
- cin >> snaps[i].x1 >> snaps[i].y1 >> snaps[i].x2 >> snaps[i].y2;
- }
- // Для каждого квадрата собираем все x-координаты для обновления префикса.
- // Для верхнего правого и нижнего правого квадратов используем s.x2;
- // для верхнего левого и нижнего левого квадратов используем -s.x1.
- vector<int> compTR, compTL, compBR, compBL;
- compTR.push_back(0);
- compTL.push_back(0);
- compBR.push_back(0);
- compBL.push_back(0);
- for (int i = 0; i < n; i++){
- if(snaps[i].x2 > 0) {
- compTR.push_back(snaps[i].x2);
- compBR.push_back(snaps[i].x2);
- }
- if(snaps[i].x1 < 0) {
- compTL.push_back(-snaps[i].x1);
- compBL.push_back(-snaps[i].x1);
- }
- }
- auto compSortUnique = [&](vector<int>& vec) {
- sort(vec.begin(), vec.end());
- vec.erase(unique(vec.begin(), vec.end()), vec.end());
- };
- compSortUnique(compTR);
- compSortUnique(compTL);
- compSortUnique(compBR);
- compSortUnique(compBL);
- // Создаем PaintLine для каждого квадрата, если в нем есть хотя бы один интервал.
- unique_ptr<PaintLine> plTR, plTL, plBR, plBL;
- if(compTR.size() >= 2) plTR = make_unique<PaintLine>(compTR);
- if(compTL.size() >= 2) plTL = make_unique<PaintLine>(compTL);
- if(compBR.size() >= 2) plBR = make_unique<PaintLine>(compBR);
- if(compBL.size() >= 2) plBL = make_unique<PaintLine>(compBL);
- // Обрабатываем снимки в обратном порядке.
- // Для каждого снимка суммируем "вклад" по четырем квадратам.
- vector<ll> ans(n, 0);
- for (int i = n - 1; i >= 0; i--){
- ll cur = 0;
- Snapshot s = snaps[i];
- // Верхний правый квадрат: обновляем, если s.x2 > 0 и s.y2 > 0.
- if(s.x2 > 0 && s.y2 > 0 && plTR) {
- cur += plTR->updatePrefix(s.x2, s.y2);
- }
- // Верхний левый квадрат: преобразуем x как -s.x1; обновляем, если s.x1 < 0 и s.y2 > 0.
- if(s.x1 < 0 && s.y2 > 0 && plTL) {
- cur += plTL->updatePrefix(-s.x1, s.y2);
- }
- // Нижний правый квадрат: преобразуем y как -s.y1; обновляем, если s.x2 > 0 и s.y1 < 0.
- if(s.x2 > 0 && s.y1 < 0 && plBR) {
- cur += plBR->updatePrefix(s.x2, -s.y1);
- }
- // Нижний левый квадрат: преобразуем оба значения; обновляем, если s.x1 < 0 и s.y1 < 0.
- if(s.x1 < 0 && s.y1 < 0 && plBL) {
- cur += plBL->updatePrefix(-s.x1, -s.y1);
- }
- ans[i] = cur;
- }
- // Выводим ответы для каждого снимка в исходном порядке.
- for(auto a : ans)
- cout << a << "\n";
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement