5.30 省选模拟赛 方格操作 扫描线 特殊性质
LINK:方格操作
首先想到的是暴力模拟 经过画图不断寻找不可解得情况 可以发现 如果可解 一定在两步之内。
证明我也不会经过不断画图 可以发现是这个样子的 不行就暴力打表.
那么模拟两遍 看是否都变成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;
}