【题解】P4214 [CERC2015] Juice Junctions

一:【题意】

\(𝑛\) 个点 \(𝑚\) 条无向边的图,每个点度数不超过 \(3\)。求出任意两个点的最小割

二:【解法】

每两个点答案只可能是 \(0,1,2,3\) ,可以哈希预处理删除一条边后所在边双情况,然后询问

0

并查集判不联通

1

是否不在同一个边双中

2

是否存在删除一条边的情况,它们不在同一个边双中

3

\(else\)

三:【代码】

#include<bits/stdc++.h>
#define Pair pair<int,int>
#define v first
#define id second
using namespace std;
typedef unsigned long long ULL;
const int N=3e3+10;
const ULL mod=1e15+7,base=1e5+7;
int n,m;
vector<Pair> mp[N];
int bcj[N];
int find(int x){
	if(x==bcj[x]) return x;
	return bcj[x]=find(bcj[x]);
}
int dfn[N],low[N],cnt;
vector<int> st;int bcc[N],idx;
ULL has[N];
void Tarjan(int u,int fa,int no){
	dfn[u]=low[u]=++cnt;
	st.push_back(u);
	for(auto e:mp[u]){
		int v=e.v,id=e.id;
		if(id==fa||id==no) continue;
		if(!dfn[v]){
			Tarjan(v,id,no);
			low[u]=min(low[u],low[v]);
		}
		else low[u]=min(low[u],dfn[v]);
	}
	//cout<<low[u]<<" "<<dfn[u]<<"\n";
	if(low[u]==dfn[u]){
		idx++;
		while(1){
			int x=st.back();st.pop_back();
			bcc[x]=idx;
			if(x==u) break;
		}
	}
}
void BCC(int e){
	cnt=idx=0;
	st.clear();
	for(int i=1;i<=n;i++) dfn[i]=low[i]=bcc[i]=0;
	for(int i=1;i<=n;i++){
		if(!dfn[i]) Tarjan(i,0,e);
	}
	if(!e) return ;
	for(int i=1;i<=n;i++){
		//cout<<bcc[i]<<"\n";
		has[i]=has[i]*base+bcc[i];
		has[i]%=mod;
	}
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++) bcj[i]=i;
	for(int i=1;i<=m;i++){
		int a,b;cin>>a>>b;
		mp[a].push_back({b,i});
		mp[b].push_back({a,i});
		a=find(a);b=find(b);
		if(a==b) continue;
		bcj[a]=b;
	}
	for(int i=1;i<=m;i++) BCC(i);
	BCC(0);
	int ans=0;
	for(int i=1;i<=n;i++){
		for(int j=i+1;j<=n;j++){
			int k;
			if(find(i)!=find(j)) k=0;
			else if(bcc[i]!=bcc[j]) k=1;
			else if(has[i]!=has[j]) k=2;
			else k=3;
			ans+=k;
			//cout<<i<<" "<<j<<" "<<k<<" "<<has[i]<<" "<<has[j]<<"\n";
		}
	}
	cout<<ans<<"\n";
	return 0;
}
posted @ 2026-01-10 09:46  Ming3398  阅读(16)  评论(0)    收藏  举报