好难的题目啊!

写个博客记录一下.

首先显然满足要求的一定是相邻行取反或者列取反的矩阵.画下图可推出来.

然后,分别考虑行列肯定是2^n,和2^m,可以看成确定一排后面的都确定了,也可以看成每一排都有两种选法.

然后考虑修改...和去重

重复即是两种情况都满足的,其实只有两种取法,即是黑白染色,确定一个点就可以确定是哪种选法.然后去判断修改是不是影响到我的去重了,假如影响到了我就不减.

然后就做完了...但是好绕啊)))网上的题解我也理解了很久,我自己的题解肯定自己理解的比较快叭~~~~~

好难喔~

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=1e6+5;
const int M=2;
const int mod=998244353;
const int iv2=(mod+1)/2;

struct date{
	ll ans;
	int cnt[N][M];//当前行/列投射到第1个列/行的值的次数.
	int f=0;//是不是已经产生了矛盾. 
	unordered_map<int,int>s[N];//记录下当前的值方便删除. 
	void del(int x,int y)
	{
		if(!s[x].count(y))	return;
		if(cnt[x][0]&&cnt[x][1])	f--;
		cnt[x][(y&1)^s[x][y]]--;
		s[x].erase(y);
		if(cnt[x][0]&&cnt[x][1])	f++;
		if(!cnt[x][0]&&!cnt[x][1])	
		ans=ans*2%mod;
	}
	void ins(int x,int y,int val)
	{
		if(!cnt[x][0]&&!cnt[x][1])		ans=ans*iv2%mod;
		if(cnt[x][0]&&cnt[x][1])		f--;
		s[x][y]=val;
		cnt[x][(y&1)^val]++;
		if(cnt[x][0]&&cnt[x][1])	f++;
	}
}r,c;

//用来去重. 
int cnt[2];
unordered_map<int,int>vis[N];
ll p[N<<2];
ll ans=0;
int main()
{
	int n,m,k;	
	scanf("%d%d%d",&n,&m,&k);
	p[0]=1;
	for(int i=1;i<=n+m;i++)	p[i]=p[i-1]*2%mod;
	r.ans=p[m];//行之间取反.
	c.ans=p[n];//列之间取反.
	for(int i=1;i<=k;i++)
	{
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		r.del(y,x);
		c.del(x,y);
		if(vis[x].count(y))	cnt[vis[x][y]^(x&1)^(y&1)]--,vis[x].erase(y);
		if(z!=-1)
		{
			vis[x][y]=z;
			r.ins(y,x,z);c.ins(x,y,z);
			cnt[vis[x][y]^(x&1)^(y&1)]++;
		}
		ans=0;
		if(!r.f)	ans+=r.ans;
		if(!c.f)	ans+=c.ans;
		ans-=(!cnt[0]);
		ans-=(!cnt[1]);
		ans=(ans%mod+mod)%mod;
		printf("%lld\n",ans);
	}
	return 0;
}