首页 > 技术文章 > 5.30 省选模拟赛 方格操作 扫描线 特殊性质

chdy 原文

LINK:方格操作

avatar
avatar
avatar

首先想到的是暴力模拟 经过画图不断寻找不可解得情况 可以发现 如果可解 一定在两步之内。

证明我也不会经过不断画图 可以发现是这个样子的 不行就暴力打表.

那么模拟两遍 看是否都变成0即可。

考虑 如何模拟这个过程 容易想到 一个格子之后的状态= 当前状态 ^ 行1的奇偶性 ^ 列1的奇偶性 ^ 当前状态.

那么得到 一个格子的状态=行的奇偶^列的奇偶。

那么每次模拟我们只需要知道每一行的1的个数 和 每一列的1的个数即可。

容易发现预处理之后 模拟的过程也可以不断维护这两个东西.

预处理 容易想到扫描线。

const int MAXN=200010;
int n,m,Q,cnt1;
struct wy{int x,l,r;}t[MAXN],g[MAXN];
inline int cmp(wy a,wy b){return a.x<b.x;}
struct jl{int l,r;int cnt,tag;}s[MAXN<<1];
int H[MAXN],W[MAXN],h[2],w[2];
inline void build(int p,int l,int r)
{
	cnt(p)=tag(p)=0;
	l(p)=l;r(p)=r;
	if(l==r)return;
	int mid=(l+r)>>1;
	build(zz,l,mid);
	build(yy,mid+1,r);
}
inline void pushdown(int p)
{
	int mid=(l(p)+r(p))>>1;
	tag(zz)^=1;tag(yy)^=1;
	cnt(zz)=mid-l(p)+1-cnt(zz);
	cnt(yy)=r(p)-mid-cnt(yy);
	tag(p)=0;
}
inline void change(int p,int l,int r)
{
	if(l<=l(p)&&r>=r(p))
	{
		cnt(p)=r(p)-l(p)+1-cnt(p);
		tag(p)=tag(p)^1;
		return;
	}
	int mid=(l(p)+r(p))>>1;
	if(tag(p))pushdown(p);
	if(l<=mid)change(zz,l,r);
	if(r>mid)change(yy,l,r);
	cnt(p)=cnt(zz)+cnt(yy);
}
int main()
{
	freopen("grid.in","r",stdin);
	freopen("grid.out","w",stdout);
	get(n);get(m);get(Q);
	rep(1,Q,i)
	{
		int get(x),get(y),get(xx),get(yx);
		t[++cnt1]=(wy){x,y,yx};
		g[cnt1]=(wy){y,x,xx};
		t[++cnt1]=(wy){xx+1,y,yx};
		g[cnt1]=(wy){yx+1,x,xx};
	}
	sort(t+1,t+1+cnt1,cmp);
	sort(g+1,g+1+cnt1,cmp);
	int flag=1;
	build(1,1,m);
	rep(1,n,i)//对行进行
	{
		while(t[flag].x<=i&&flag<=cnt1)change(1,t[flag].l,t[flag].r),++flag;
		H[i]=cnt(1);
	}
	build(1,1,n);
	flag=1;
	rep(1,m,i)
	{
		while(g[flag].x<=i&&flag<=cnt1)change(1,g[flag].l,g[flag].r),++flag;
		W[i]=cnt(1);
	}
	ll ans=0;
	for(int T=1;T<=2;++T)
	{
		h[1]=h[0]=w[1]=w[0]=0;
		rep(1,n,i)ans+=H[i],++h[H[i]&1];
		rep(1,m,i)++w[W[i]&1];
		rep(1,n,i)H[i]=w[(H[i]&1)^1];
		rep(1,m,i)W[i]=h[(W[i]&1)^1];
	}
	rep(1,n,i)if(H[i])return puts("-1"),0;
	putl(ans);
	return 0;
}

推荐阅读