CF1373G. Pawns

题目描述

题解

如果一个格子可以放多个棋子,且棋子直接斜着走上去,那我们可以知道每个格子上会有多少棋子。

现在我们考虑将棋子往上挪。

如果我们最后扩充的棋盘行数为 $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;
}

 

posted @ 2021-10-21 19:42  xjqxjq  阅读(35)  评论(0编辑  收藏  举报