codeforces 1373G Pawns 线段树
题意
给一个\(n\times n\)的空棋盘,棋盘的第\(k\)列是一个特殊的列,有\(m\)次操作,每次增加一个棋子或者移走一个棋子,如果能使用以下规则将所有棋子移动到第\(k\)列,那么这个棋盘是好的。
- 在格子\((x,y)\)位置的棋子,能移动到\((x,y+1),(x+1,y+1),(x-1,y+1)\);
- 你能做任意次移动;
- 棋子不能移动到棋盘外;
- 每个格子只能放一个棋子。
你可以在棋盘顶部增加一些行,使棋盘能够是好的。每次操作后,问棋盘至少增加多少行,可以将它变成好的。
分析
令\(f[x]\)为有多少棋子要在第\(x\)行上面,答案为\(max(f[x]+x-n,0)\)。证明略。
Code
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<sstream>
#include<cstdio>
#include<string>
#include<vector>
#include<bitset>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define rep(i,x,n) for(int i=x;i<=n;i++)
#define per(i,n,x) for(int i=n;i>=x;i--)
#define sz(a) int(a.size())
#define rson mid+1,r,p<<1|1
#define pii pair<int,int>
#define lson l,mid,p<<1
#define ll long long
#define pb push_back
#define mp make_pair
#define se second
#define fi first
using namespace std;
const double eps=1e-8;
const int mod=1e9+7;
const int N=4e5+10;
const int inf=1e9;
int n,k,m;
map<pii,int>vis;
int mx[N<<2],tag[N<<2];
int a[N];
void pd(int p,int k){
mx[p<<1]+=k;
tag[p<<1]+=k;
mx[p<<1|1]+=k;
tag[p<<1|1]+=k;
tag[p]=0;
}
void up(int dl,int dr,int l,int r,int p,int k){
if(l==dl&&r==dr){
mx[p]+=k;
tag[p]+=k;
return;
}
int mid=l+r>>1;
pd(p,tag[p]);
if(dr<=mid) up(dl,dr,lson,k);
else if(dl>mid) up(dl,dr,rson,k);
else up(dl,mid,lson,k),up(mid+1,dr,rson,k);
mx[p]=max(mx[p<<1],mx[p<<1|1]);
}
int main(){
ios::sync_with_stdio(false);
//freopen("in","r",stdin);
cin>>n>>k>>m;
rep(i,1,m){
int x,y;
cin>>x>>y;
int p=abs(x-k)+y;
if(vis[mp(x,y)]){
up(1,p,1,2*n,1,-1);
a[p]--;
if(a[p]==0) up(p,p,1,2*n,1,-p+1);
vis[mp(x,y)]=0;
}else{
up(1,p,1,2*n,1,1);
if(a[p]==0) up(p,p,1,2*n,1,p-1);
++a[p];
vis[mp(x,y)]=1;
}
cout<<max(0,mx[1]-n)<<'\n';
}
return 0;
}