题解
如果一个格子可以放多个棋子,且棋子直接斜着走上去,那我们可以知道每个格子上会有多少棋子。
现在我们考虑将棋子往上挪。
如果我们最后扩充的棋盘行数为 $r$ ,那么假设第 $j$ 格子之后一共有 $a_j$ 个棋子,那么一定满足 $a_j \le r-j+1$ 。
移项后就是 $a_j+j-1-n \le r-n$ ,可以看出右边部分就是扩充的行数,因此我们只要维护左边的最大值即可。
效率: $O(n \log n)$ 。
代码
#include<bits/stdc++.h> #define M make_pair using namespace std; const int N=4e5+5; int n,c,m,a[N<<2],g[N<<2]; multiset<int>s; map<pair<int,int>,bool>f; inline int A(int x){return x>0?x:-x;} #define Ls k<<1 #define Rs k<<1|1 #define mid ((l+r)>>1) void build(int k,int l,int r){ if (l==r){a[k]=l-1-n;return;} build(Ls,l,mid);build(Rs,mid+1,r); a[k]=max(a[Ls],a[Rs]); } inline void push(int k,int v){a[k]+=v;g[k]+=v;} inline void down(int k){ push(Ls,g[k]);push(Rs,g[k]);g[k]=0; } void upd(int k,int l,int r,int R,int v){ if (r<=R) return push(k,v); if (g[k]) down(k); upd(Ls,l,mid,R,v); if (mid<R) upd(Rs,mid+1,r,R,v); a[k]=max(a[Ls],a[Rs]); } int qry(int k,int l,int r,int R){ if (r<=R) return a[k]; if (g[k]) down(k); if (mid>=R) return qry(Ls,l,mid,R); return max(qry(Ls,l,mid,R),qry(Rs,mid+1,r,R)); } int main(){ scanf("%d%d%d",&n,&c,&m); build(1,1,n<<1); for (int x,y,v,i=1;i<=m;i++){ scanf("%d%d",&x,&y); v=A(x-c)+y; if (!f.count(M(x,y))){ f[M(x,y)]=1; upd(1,1,n<<1,v,1); s.insert(v); } else{ f.erase(M(x,y)); upd(1,1,n<<1,v,-1); s.erase(s.find(v)); } if (s.empty()) puts("0"); else printf("%d\n",max(0,qry(1,1,n<<1,*s.rbegin()))); } return 0; }