BZOJ2430&&洛谷P3225[HNOI2012]礦場搭建
阿新 • • 發佈:2018-12-11
無向圖tarjan求割點
很顯然,我們求出所有聯通分量後,若這個聯通分量內有
1個割點,那麼只能在這個點上建出口,因為這個點壞了其他點就出不去了
2+個割點,那麼這個聯通分量是安全的,因為其中一個壞了還能走另一個
0個割點,那麼這個聯通分量至少需要兩個出口,否則也無法出去
然後方案數就根據上面這些亂搞一下就好了
程式碼
//By AcerMo
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lli long long int
using namespace std;
const int M=200500;
int n,m,ans,emm;
int to[M],nxt[M],head[M],cnt;
int dfn[M],low[M],cut[M],fa[M],ind,ti;
inline int read()
{
int x=0;char ch=getchar();
while (ch>'9'||ch<'0') ch=getchar();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
inline void add(int x,int y)
{
to[++cnt]=y;nxt[cnt]=head[x];head[x]=cnt;
to[++cnt]=x;nxt[cnt]=head[y];head[y]=cnt;
return ;
}
inline void tarjan(int x,int f)
{
low[x]=dfn[x]=++ind;int son=0;
for (int i=head[x];i;i=nxt[i])
if (!dfn[to[i]])
{
tarjan(to[i],x);son++;
low[x]=min(low[x],low[to[i]]);
if ( low[to[i]]>=dfn[x]) cut[x]=1;
}
else if (f!=to[i]) low[x]=min(low[x],dfn[to[i]]);
if (son==1&&!f) cut[x]=0;
return ;
}
inline void dfs(int x)
{
fa[x]=ti;
if (cut[x]) return ;emm++;
for (int i=head[x];i;i=nxt[i])
{
if (fa[to[i]]!=ti&&cut[to[i]]) ans++,fa[to[i]]=ti;
if (!fa[to[i]]&&!cut[to[i]]) dfs(to[i]);
}
return ;
}
inline void clean()
{
fill(low,low+n+1,0);
fill(dfn,dfn+n+1,0);fill(cut,cut+n+1,0);
fill(head,head+n+1,0);fill(fa,fa+n+1,0);
return (void)(ti=ind=n=cnt=0);
}
signed main()
{
int cas=0;
while ((m=read())&&m)
{
int x,y;clean();
lli qlm=0,que=1;
for (int i=1;i<=m;i++)
{
x=read(),y=read();
add(x,y),n=max(n,max(x,y));
}
for (int i=1;i<=n;i++)
if (!dfn[i]) tarjan(i,0);
for (int i=1;i<=n;i++)
if (!fa[i]&&!cut[i])
{
ti++;ans=emm=0;dfs(i);
if (!ans) qlm+=2,que*=(emm*(emm-1)/2);
if (ans==1) qlm++,que*=emm;
}
printf("Case %d: %lld %lld\n",++cas,qlm,que);
}
return 0;
}