C/C++教程

2022.02.27 CF811E Vladik and Entertaining Flags

本文主要是介绍2022.02.27 CF811E Vladik and Entertaining Flags,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

2022.02.27 CF811E Vladik and Entertaining Flags

https://www.luogu.com.cn/problem/CF811E

Step 1 题意

在一个 n*m 的网格上每个格子都有颜色,q 次询问,每次询问只保留 l 至 r 列时有多少个四连通的颜色块。两个格子同色但不连通算在不同的颜色块内。

Step 2 分析

这道题我首先大力找到一个错误规律,这个暂且不说,直接上正解。

对于每一列的格子搞线段树,记录每列有几个连通块,每列的最左侧和最右侧的节点属于哪个连通块。

合并的时候合并两个连通块相邻的两列,如果颜色一致并且fa不一样,总连通块的数量减一。不过需要初始化一下相邻两列格子的并查集。

Step 3 代码如下

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

const int N=1e5+10;
int n,m,q,mapi[15][N],fa[N*15];
int tot;
struct node{
	int x,y,L[15],R[15],sum;
}t[N<<4];

inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
inline int find(int x){
	return x==fa[x]?x:fa[x]=find(fa[x]);
}
inline node update(node x,node y,int l,int r){
	node ans;
	ans.sum=x.sum+y.sum;
	for(int i=1;i<=n;i++)
	fa[x.L[i]]=x.L[i],fa[x.R[i]]=x.R[i],
	fa[y.L[i]]=y.L[i],fa[y.R[i]]=y.R[i];
	for(int i=1;i<=n;i++)ans.L[i]=x.L[i],ans.R[i]=y.R[i];
	for(int i=1;i<=n;i++)
	if(mapi[i][l]==mapi[i][r]){
		int xi=find(fa[x.R[i]]);
		int yi=find(fa[y.L[i]]);
		if(xi!=yi)fa[xi]=yi,--ans.sum;
	}
	for(int i=1;i<=n;i++)
	ans.L[i]=find(ans.L[i]),ans.R[i]=find(ans.R[i]);
	return ans;
}
inline void build(int x,int l,int r){
	if(l==r){
		for(int i=1;i<=n;i++)
		if(mapi[i][l]==mapi[i-1][l])
		t[x].L[i]=t[x].R[i]=t[x].L[i-1];
		else t[x].L[i]=t[x].R[i]=++tot,++t[x].sum;
		return ;
	}
	int mid=(l+r)>>1;
	build(x<<1,l,mid);
	build(x<<1|1,mid+1,r);
	t[x]=update(t[x<<1],t[x<<1|1],mid,mid+1);
}
inline node query(int x,int l,int r,int L,int R){
	if(l>=L&&r<=R)return t[x];
	int mid=(l+r)>>1;
	int flaga=0,flagb=0;
	node a,b,ans;
	if(L<=mid)a=query(x<<1,l,mid,L,R),flaga=1;
	if(R>mid)b=query(x<<1|1,mid+1,r,L,R),flagb=1;
	if(flaga&&!flagb)ans=a;
	else if(flagb&&!flaga)ans=b;
	else if(flaga&&flagb)ans=update(a,b,mid,mid+1);
	return ans;
}

signed main(){
	n=read();m=read();q=read();
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)mapi[i][j]=read();
	//cout<<"Case 1 "<<endl;
	build(1,1,m);
	//cout<<"Case 2 "<<endl;
	for(int i=1;i<=q;i++){
		int u,v;
		u=read();v=read();
		node fin=query(1,1,m,u,v);
		cout<<fin.sum<<endl; 
	}
	return 0;
}
这篇关于2022.02.27 CF811E Vladik and Entertaining Flags的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!