题意
题解
棋子 ( x , y ) (x,y) (x,y) 能安排在 y ≥ ∣ k − y ∣ + x y\geq \lvert k-y\rvert + x y≥∣k−y∣+x 的位置。
令 f ( j ) f(j) f(j) 代表 i ≥ j i\geq j i≥j 必须安排的棋子数量,那么对于合法的最大行号 t t t,应该满足 f ( j ) ≤ t − j + 1 f(j)\leq t - j + 1 f(j)≤t−j+1。根据 Hall 定理,将 f ( j ) f(j) f(j) 看作二分图需要构造完备匹配的一侧点集(显然位置连续的点集能获得更大的 t t t),则可以证明满足上述条件时存在一组合法的点集安排。
使用可以区间修改的线段树维护 f ( j ) + j − 1 f(j)+j-1 f(j)+j−1,查询使 f ( j ) > 0 f(j)>0 f(j)>0 的前缀 [ 0 , j ] [0,j] [0,j] 即可。总时间复杂度 O ( n log n ) O(n\log n) O(nlogn)。
#include <bits/stdc++.h>
using namespace std;
constexpr int MAXN = 2E5 + 5, SZ = 1 << 20, INF = 0x3f3f3f3f;
int N, K, M;
struct ST
{
int dat[SZ], lz[SZ];
void init(int k = 0, int l = 0, int r = N * 2)
{
if (r - l == 1)
{
dat[k] = l - 1;
return;
}
int m = (l + r) / 2, chl = k * 2 + 1, chr = k * 2 + 2;
init(chl, l, m), init(chr, m, r);
lz[k] = 0;
dat[k] = max(dat[chl], dat[chr]);
}
void pushdown(int k)
{
if (lz[k] != 0)
{
int chl = k * 2 + 1, chr = k * 2 + 2;
int x = lz[k];
lz[k] = 0;
lz[chl] += x, dat[chl] += x;
lz[chr] += x, dat[chr] += x;
}
}
void change(int a, int b, int x, int k = 0, int l = 0, int r = N * 2)
{
if (r <= a || b <= l)
return;
if (a <= l && r <= b)
{
lz[k] += x, dat[k] += x;
return;
}
pushdown(k);
int m = (l + r) / 2, chl = k * 2 + 1, chr = k * 2 + 2;
change(a, b, x, chl, l, m), change(a, b, x, chr, m, r);
dat[k] = max(dat[chl], dat[chr]);
}
int ask(int a, int b, int k = 0, int l = 0, int r = N * 2)
{
if (r <= a || b <= l)
return -INF;
if (a <= l && r <= b)
return dat[k];
pushdown(k);
int m = (l + r) / 2, chl = k * 2 + 1, chr = k * 2 + 2;
return max(ask(a, b, chl, l, m), ask(a, b, chr, m, r));
}
} tr;
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> N >> K >> M;
--K;
set<pair<int, int>> ps;
multiset<int> ys;
tr.init();
for (int i = 0; i < M; ++i)
{
int x, y;
cin >> x >> y;
--x, --y;
int _y = abs(K - x) + y;
if (ps.count({x, y}))
{
ps.erase({x, y});
ys.erase(ys.find(_y));
tr.change(0, _y + 1, -1);
}
else
{
ps.insert({x, y});
ys.insert(_y);
tr.change(0, _y + 1, 1);
}
int res;
if (ys.size() == 0)
res = 0;
else
{
int pos = *--ys.end();
int t = tr.ask(0, pos + 1);
res = max(0, t - N + 1);
}
cout << res << '\n';
}
return 0;
}