【题解】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;
}

浙公网安备 33010602011771号