[CF1303F] Number of Components

\(\text{Problem}:\)题目链接

\(\text{Solution}:\)

观察 \(c_{i}\leq c_{i+1}\) 的性质。这说明,对于一个颜色 \(C\),所有 \(a_{i,j}=C\) 的位置一定是先全部覆盖,然后再逐个删除

对于一次操作,记颜色 \(C_{2}\) 覆盖掉了 \(C_{1}\),原图为 \(A\),新图为 \(B\)。从 \(A\rightarrow B\),相当于颜色 \(C_{2}\) 的合并;从 \(A\rightarrow B\),相当于颜色 \(C_{1}\) 的分裂。逆向考虑,发现从 \(B\rightarrow A\),相当于颜色 \(C_{1}\) 的合并。我们发现,把一个操作分为两个操作后,由于满足第一段中 \(c_{i}\leq c_{i+1}\) 得到的性质,一种颜色 \(C\) 一定是合并结束后再分裂。那么答案对于一种颜色是独立的!所以,我们可以对于每种颜色单独考虑贡献,把分裂看作反向合并,对答案贡献也取反即可。

此题由于空间限制较紧,需要较好的实现方式。具体的,只需要开 \(O(n^2)\) 个并查集。对于每种颜色算完之后,把与这种颜色有关的位置上的 \(f_{i,j}\) 清空即可。

\(\text{Code}:\)

#include <bits/stdc++.h>
#pragma GCC optimize(3)
//#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
using namespace std; const int N=310, M=2000010;
inline int read()
{
	int s=0, w=1; ri char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
	while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
	return s*w;
}
int n,m,Q,Ans[M],a[N][N],book[N*N];
int f[N*N];
inline int Find(int x) { if(!x) return 0; return f[x]^x?f[x]=Find(f[x]):x; }
inline int Merge(int x,int y)
{
	int fx=Find(x), fy=Find(y);
	if(fx==fy) return 0;
	f[fx]=fy;
	return 1;
}
inline int ID(int x,int y) { return (x-1)*m+y; }
struct Node { int x,y,id; };
vector<Node> g1[M],g2[M];
const int step[4][2]={{0,1},{1,0},{-1,0},{0,-1}};
signed main()
{
	n=read(), m=read(), Q=read();
	int Mx=0;
	for(ri int i=1;i<=Q;i++)
	{
		int x,y,c;
		x=read(), y=read(), c=read();
		Mx=max(Mx,c);
		if(a[x][y]^c)
		{
			g1[a[x][y]].eb((Node){x,y,i});
			a[x][y]=c;
			g2[a[x][y]].eb((Node){x,y,i});
		}
	}
	for(ri int i=1;i<=n;i++)
	for(ri int j=1;j<=m;j++)
	g1[a[i][j]].eb((Node){i,j,Q+1});
	for(ri int i=0;i<=Mx;i++) reverse(g1[i].begin(),g1[i].end());
	for(ri int i=0;i<=Mx;i++)
	{
		for(auto j:g1[i])
		{
			book[ID(j.x,j.y)]=1;
			if(!f[ID(j.x,j.y)]) f[ID(j.x,j.y)]=ID(j.x,j.y);
			Ans[j.id]--;
			for(ri int k=0;k<4;k++)
			{
				int u=j.x+step[k][0];
				int v=j.y+step[k][1];
				if(u<1||u>n||v<1||v>m||!book[ID(u,v)]) continue;
				Ans[j.id]+=Merge(ID(u,v),ID(j.x,j.y));
			}
		}
		for(auto j:g1[i]) book[ID(j.x,j.y)]=f[ID(j.x,j.y)]=0;
	}
	for(ri int i=0;i<=Mx;i++)
	{
		for(auto j:g2[i])
		{
			book[ID(j.x,j.y)]=1;
			if(!f[ID(j.x,j.y)]) f[ID(j.x,j.y)]=ID(j.x,j.y);
			Ans[j.id]++;
			for(ri int k=0;k<4;k++)
			{
				int u=j.x+step[k][0];
				int v=j.y+step[k][1];
				if(u<1||u>n||v<1||v>m||!book[ID(u,v)]) continue;
				Ans[j.id]-=Merge(ID(u,v),ID(j.x,j.y));
			}
		}
		for(auto j:g2[i]) book[ID(j.x,j.y)]=f[ID(j.x,j.y)]=0;
	}
	Ans[0]=1;
	for(ri int i=1;i<=Q;i++)
	{
		Ans[i]+=Ans[i-1];
		printf("%d\n",Ans[i]);
	}
	return 0;
}
posted @ 2021-02-24 10:34  zkdxl  阅读(47)  评论(0编辑  收藏  举报