Quantum
Problem Statementa
Solution
We have an $n \times m $ grid, initially empty. We will be given points. Each time we add a point, we must choose a point in the grid such that the sum of distances from all added points to is minimized.
Subtask 1: 5 points
Grid is . Just check whether or is better.
Subtask 2: 15 points
Use a 2D array initialized to zeros.
For each new point :
- Add distance to all cells.
- Take minimum.
Time complexity: .
Subtask 3: 30 points
We use a greedy/median idea.
For 1D: given , to minimize , pick median.
So:
- Maintain arrays of 's and 's separately.
- Each time, sort them, pick median, compute sum of distances.
Time complexity: .
Subtask 4: 100 points
Optimize subtask 3 with data structures:
- Ordered set → find median in .
- Lazy segment tree → range update/query for sums.
Final complexity: .
Implementation
cpp
#include <bits/stdc++.h>
#include <filesystem>
using namespace std;
using ll = long long;
// Segment tree for sum over a fixed range [1..N]
struct SegTree {
int n;
vector<ll> t;
SegTree(int _n): n(_n), t(4*n, 0) {}
void update(int idx, ll val, int v, int tl, int tr) {
if (tl == tr) {
t[v] += val;
} else {
int tm = (tl + tr) >> 1;
if (idx <= tm) update(idx, val, v<<1, tl, tm);
else update(idx, val, v<<1|1, tm+1, tr);
t[v] = t[v<<1] + t[v<<1|1];
}
}
void update(int idx, ll val) { update(idx, val, 1, 1, n); }
ll query(int l, int r, int v, int tl, int tr) {
if (l > r) return 0;
if (l == tl && r == tr) return t[v];
int tm = (tl + tr) >> 1;
return query(l, min(r, tm), v<<1, tl, tm)
+ query(max(l, tm+1), r, v<<1|1, tm+1, tr);
}
ll query(int l, int r) { return query(l, r, 1, 1, n); }
};
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m, C;
cin >> n >> m >> C;
vector<int> xs(C), ys(C);
for(int i=0;i<C;i++) cin>>xs[i]>>ys[i];
// Create segment trees for X and Y: counts and sums
SegTree cntX(n), sumX(n);
SegTree cntY(m), sumY(m);
vector<ll> ans(C);
for(int k=1;k<=C;k++){
int x = xs[k-1], y = ys[k-1];
cntX.update(x, 1);
sumX.update(x, x);
cntY.update(y, 1);
sumY.update(y, y);
// total count and sum
ll totalX = sumX.query(1, n);
ll totalCntX = cntX.query(1, n);
auto costX = [&](int X){
ll leftCnt = cntX.query(1, X);
ll leftSum = sumX.query(1, X);
ll rightCnt = totalCntX - leftCnt;
ll rightSum = totalX - leftSum;
return X*leftCnt - leftSum + rightSum - X*rightCnt;
};
// Ternary search on [1..n]
int l = 1, r = n;
while(r - l > 3){
int m1 = l + (r - l)/3;
int m2 = r - (r - l)/3;
if(costX(m1) > costX(m2)) l = m1;
else r = m2;
}
ll bestX = LLONG_MAX;
for(int X=l; X<=r; ++X) bestX = min(bestX, costX(X));
// Similarly for Y
ll totalY = sumY.query(1, m);
ll totalCntY = cntY.query(1, m);
auto costY = [&](int Y){
ll lc = cntY.query(1, Y);
ll ls = sumY.query(1, Y);
ll rc = totalCntY - lc;
ll rs = totalY - ls;
return Y*lc - ls + rs - Y*rc;
};
l = 1; r = m;
while(r - l > 3){
int m1 = l + (r - l)/3;
int m2 = r - (r - l)/3;
if(costY(m1) > costY(m2)) l = m1;
else r = m2;
}
ll bestY = LLONG_MAX;
for(int Y=l; Y<=r; ++Y) bestY = min(bestY, costY(Y));
ans[k-1] = bestX + bestY;
}
for(ll v: ans) cout<<v<<"\n";
return 0;
}
