1. 程式人生 > 其它 >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;
}