Mining Your Own Business UVA - 1108
题意:
本题有n个通道,每个通道连接两个点。
现在要求你安插最少的逃脱通道,保证有任意一个点坍塌时,所有的矿工都可以逃脱。
思路:
- 可以首先想到求割点
- 之后求 点双连通,可以发现一个 点双连通里只有一个割点时,才用设置逃脱点。
特别注意
:当只有一个 点双连通分量时,那么要设置两个逃脱点,才可以安全逃脱。 C n 2 C_{n}^{2} Cn2注意
:记得开longlong
AC
#include <iostream>
#include <cstring>
#include <algorithm>
#include <stack>
#include <vector>
#define pb push_back
#define mst(x,a) memset(x,a,sizeof(x))
#define fzhead EDGE(int _u, int _v, int _next)
#define fzbody u(_u), v(_v), next(_next)
#define fori(i,x,y) for(int i=(x); i<(y); i++)
#define For(i,x,y) for(int i=(x); i<=(y); i++)
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int maxm=2e5+10;
struct EDGE{
int u,v,next;
EDGE(){}
fzhead:fzbody{}
}e[maxm];
int head[maxm], tot;
int cut[maxn], low[maxn], dfn[maxn], bccno[maxn], dfs_clock, bcc_cnt;
vector<int> bcc[maxn];
stack<EDGE> s;
int ls[maxn],cnt0,m,n;
int L[maxn], R[maxn];
void add(int bg, int to){
e[tot]=EDGE(bg,to,head[bg]);
head[bg]=tot++;
}
void init(){
dfs_clock=bcc_cnt=0;
tot=2;
mst(cut,0);mst(low,0);
mst(head,-1);mst(dfn,0);
mst(bccno,0);
cnt0=0;
int u,v;
For(i,1,m){
cin>>L[i]>>R[i];
ls[++cnt0]=L[i];
ls[++cnt0]=R[i];
}
sort(ls+1,ls+1+cnt0);
n=unique(ls+1,ls+1+cnt0)-ls-1;
For(i,1,m){
u = lower_bound(ls+1,ls+1+n,L[i])-ls;
v = lower_bound(ls+1,ls+1+n,R[i])-ls;
add(u,v);
add(v,u);
}
while(!s.empty())s.pop();
}
int root;
void tarjan(int u, int f){
low[u]=dfn[u]=++dfs_clock;
int child=0;
for(int i=head[u]; i!=-1; i=e[i].next){
int v=e[i].v;
EDGE edge={u,v,0};
if(!dfn[v]){
s.push(edge);
child++;
tarjan(v,u);
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u]){
if(root!=u||child>1)cut[u]=1;
bcc[++bcc_cnt].clear();
for(;;){
EDGE x = s.top();s.pop();
if(bccno[x.u]!=bcc_cnt){
bcc[bcc_cnt].pb(x.u);bccno[x.u]=bcc_cnt;
}
if(bccno[x.v]!=bcc_cnt){
bcc[bcc_cnt].pb(x.v);bccno[x.v]=bcc_cnt;
}
if(x.u==u&&x.v==v)break;
}
}
}else if(dfn[v]<dfn[u]&&v!=f){
s.push(edge);
low[u]=min(low[u],dfn[v]);
}
}
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int kase=0;
while(cin>>m,m){
init();
For(u,1,n)if(!dfn[u])root=u,dfs_clock=0,tarjan(u,-1);
ll ans1=0,ans2=1;
For(i,1,bcc_cnt){
int cnt1=0;
fori(j,0,bcc[i].size())if(cut[bcc[i][j]])cnt1++;
// cout<<"i----bcc[i].size()----";
//cout<<i<<' '<<bcc[i].size()<<endl;
//cout<<"yuansu of this bcc------"<<endl;
//fori(j,0,bcc[i].size())cout<<bcc[i][j]<<' ';//if(cut[bcc[i][j]])cnt1++;
//cout<<endl;
if(cnt1==1){
// cout<<"i----bcc[i].size()----";
// cout<<i<<' '<<bcc[i].size()<<endl;
// cout<<"yuansu of this bcc------"<<endl;
// fori(j,0,bcc[i].size())cout<<bcc[i][j]<<' ';//if(cut[bcc[i][j]])cnt1++;
// cout<<endl;
ans1++;ans2*=(ll)(bcc[i].size()-1);
}
}
if(bcc_cnt==1){
ans1=2;ans2=(ll)(n-1)*n/2;
}
cout<<"Case "<<++kase<<": ";//2 4"
cout<<ans1<<' '<<ans2<<endl;
}
return 0;
}