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;
}
posted @ 2020-07-02 13:47  xyq0220  阅读(206)  评论(0编辑  收藏  举报