链接
http://acm.hdu.edu.cn/showproblem.php?pid=3844
题解
画一画样例,然后可以感觉到答案肯定就是在在广义圆方树上把所有叶子节点(方点)所代表的那些双连通分量中的非割点给选中
但是不用真的建圆方树,因为我只需要叶子节点,树上度为
1
1
1的就是叶子节点,我只要找出所有双联通分量,找到那些只包含一个割点的双连通分量就好了
代码
#include <bits/stdc++.h>
#define maxn 100010
#define maxe 100010
using namespace std;
struct Graph
{
int etot, head[maxn], to[maxe], next[maxe], w[maxe];
void clear(int N)
{
for(int i=1;i<=N;i++)head[i]=0;
etot=0;
}
void adde(int a, int b, int c=0){to[++etot]=b;w[etot]=c;next[etot]=head[a];head[a]=etot;}
}G;
struct BiconnectedComponent
{
int dfn[maxn], low[maxn], iscut[maxn], bccno[maxn], tim, tot;
vector<int> bcc[maxn];
typedef pair<int,int> pii;
stack<pii> s;
void dfs(Graph &G, int pos, int pre)
{
int ch=0;
dfn[pos]=low[pos]=++tim;
for(auto p=G.head[pos];p;p=G.next[p])
if(!dfn[G.to[p]])
{
ch++;
s.push(pii(pos,G.to[p]));
dfs(G,G.to[p],pos);
low[pos]=min(low[pos],low[G.to[p]]);
if(low[G.to[p]]>=dfn[pos])
{
iscut[pos]=1;
bcc[++tot].clear();
while(1)
{
auto u=s.top().first, v=s.top().second; s.pop();
if(bccno[u]!=tot)bcc[tot].push_back(u), bccno[u]=tot;
if(bccno[v]!=tot)bcc[tot].push_back(v), bccno[v]=tot;
if(u==pos and v==G.to[p])break;
}
}
}
else if(dfn[G.to[p]]<dfn[pos] and G.to[p]!=pre)
{
s.push(pii(pos,G.to[p]));
low[pos]=min(low[pos],dfn[G.to[p]]);
}
if(pre<0 and ch==1)iscut[pos]=0;
}
void run(Graph &G, int N)
{
int i;
for(i=1;i<=N;i++)bccno[i]=iscut[i]=dfn[i]=0;
tim=tot=0;
for(i=1;i<=N;i++)if(!dfn[i])dfs(G,i,-1);
}
}BCC;
int M, mark[maxn];
long long cnt;
int main()
{
ios::sync_with_stdio(false);
int i, u ,v, kase=0, ans;
while(cin>>M, M)
{
cout<<"Case "<<++kase<<": ";
G.clear(100000);
for(i=1;i<=M;i++)
{
cin>>u>>v;
G.adde(u,v);
G.adde(v,u);
}
BCC.run(G,100000);
ans=0;
cnt=1;
for(i=1;i<=BCC.tot;i++)
{
int cut_cnt=0;
for(auto x:BCC.bcc[i])if(BCC.iscut[x])cut_cnt++;
if(cut_cnt==1)cnt*=BCC.bcc[i].size()-1, ans++;
}
if(BCC.tot==1)
{
ans=2;
long long t=BCC.bcc[1].size();
cnt=t*(t-1)/2;
}
cout<<ans<<' '<<cnt<<endl;
}
return 0;
}