步骤:tarjan求割点,tarjan求点双连通分量并建图,对得到的森林进行dfs求出两个量sum[i]和dis[i],tarjan离线求LCA。
#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
const int maxn=100005;
struct edge
{
int to,next;
}oee[maxn*4],ee[maxn*8];
int oe[maxn],e[maxn*2],ecnt,oecnt;
int n;
void addedge1(int u,int v)
{
oee[oecnt].to=v;oee[oecnt].next=oe[u];oe[u]=oecnt++;
oee[oecnt].to=u;oee[oecnt].next=oe[v];oe[v]=oecnt++;
}
void addedge2(int u,int v)
{
ee[ecnt].to=v;ee[ecnt].next=e[u];e[u]=ecnt++;
ee[ecnt].to=u;ee[ecnt].next=e[v];e[v]=ecnt++;
}
void edgeinit()
{
memset(oe,-1,sizeof(oe));oecnt=0;
memset(e,-1,sizeof(e));ecnt=0;
}
int size[maxn*2],id[maxn],idcnt;
void init0()
{
memset(size,0,sizeof(size));
int i;
for(i=1;i<=n;++i)
id[i]=-i;
idcnt=0;
}
//求割点
int dfn1[maxn*2],low1[maxn*2],ind1;
bool cid[maxn];
void tarjan1(int f,int u,bool flag)
{
dfn1[u]=low1[u]=++ind1;
int i,j,v,cnt=0;
for(i=oe[u];i!=-1;i=oee[i].next)
{
v=oee[i].to;
if(v==f)
continue;
if(dfn1[v]!=-1)
{
low1[u]=min(low1[u],dfn1[v]);
}
else
{
cnt++;
tarjan1(u,v,false);
low1[u]=min(low1[u],low1[v]);
if(dfn1[u]<=low1[v]&&flag==false)
{
if(cid[u]==false)
{
cid[u]=true;
id[u]=++idcnt;
size[idcnt]=1;
}
}
}
}
if(flag&&cnt>1)
{
if(cid[u]==false)
{
cid[u]=true;
id[u]=++idcnt;
size[idcnt]=1;
}
}
}
void work1()
{
memset(dfn1,-1,sizeof(dfn1));
memset(low1,-1,sizeof(low1));
ind1=0;
memset(cid,false,sizeof(cid));
int i;
for(i=1;i<=n;++i)
{
if(dfn1[i]==-1)
{
tarjan1(-1,i,true);
}
}
}
//求双连通分量
stack<int> stk2;
int dfn2[maxn*2],low2[maxn*2],ind2;
void tarjan2(int f,int u)
{
dfn2[u]=low2[u]=++ind2;
stk2.push(u);
int i,v,tv;
for(i=oe[u];i!=-1;i=oee[i].next)
{
v=oee[i].to;
if(v==f)
continue;
if(dfn2[v]!=-1)
{
low2[u]=min(low2[u],dfn2[v]);
}
else
{
tarjan2(u,v);
low2[u]=min(low2[u],low2[v]);
if(dfn2[u]<=low2[v])
{
idcnt++;
do
{
tv=stk2.top();stk2.pop();
size[idcnt]++;
if(cid[tv])
{
addedge2(idcnt,id[tv]);
}
else
{
id[tv]=idcnt;
}
}while(tv!=v);
size[idcnt]++;
if(cid[u])
addedge2(idcnt,id[u]);
else
id[u]=idcnt;
}
}
}
}
void work2()
{
while(!stk2.empty())
stk2.pop();
memset(dfn2,-1,sizeof(dfn2));
memset(low2,-1,sizeof(low2));
ind2=0;
int i;
for(i=1;i<=n;++i)
if(dfn2[i]==-1)
tarjan2(-1,i);
}
//新图中dfs预处理出dis和sum 每个点距离树根的距离以及点数和
int dis3[maxn*2],sum3[maxn*2];
void dfs3(int f,int u,int num,int d)
{
dis3[u]=d;sum3[u]=num+size[u];
int i,v;
for(i=e[u];i!=-1;i=ee[i].next)
{
v=ee[i].to;
if(v==f)
continue;
dfs3(u,v,sum3[u],d+1);
}
}
void work3()
{
memset(dis3,-1,sizeof(dis3));
memset(sum3,0,sizeof(sum3));
int i;
for(i=1;i<=idcnt;++i)
{
if(dis3[i]==-1)
{
dfs3(-1,i,0,0);
}
}
}
//tarjan 离线求LCA
struct ord
{
int ans,lab;
ord(){}
ord(int a,int l)
{
ans=a,lab=l;
}
};
bool cmp(const ord &a,const ord &b)
{
return a.lab<b.lab;
}
struct need
{
int v,lab;
need(){}
need(int a,int b)
{
v=a;lab=b;
}
};
vector<ord> v1;
vector<need> v2[maxn*2];
int f1[maxn],f2[maxn*2];
int col[maxn*2];
bool hash[maxn];
int find(int x)
{
if(f2[x]==x)
return x;
else
return f2[x]=find(f2[x]);
}
void dfs44(int f,int u,int idd)
{
hash[u]=true;
f1[u]=idd;
int i,v;
for(i=oe[u];i!=-1;i=oee[i].next)
{
v=oee[i].to;
if(hash[v])
continue;
dfs44(u,v,idd);
}
}
void tarjan4(int f,int u)
{
int i,v,l,tans,lca;
f2[u]=u;col[u]=1;
for(i=e[u];i!=-1;i=ee[i].next)
{
v=ee[i].to;
if(v==f)
continue;
if(col[v]==0)
{
tarjan4(u,v);
f2[v]=u;
}
}
for(i=0;i<v2[u].size();++i)
{
v=v2[u][i].v;l=v2[u][i].lab;
if(col[v]==2)
{
lca=find(v);
tans=sum3[u]+sum3[v]-2*sum3[lca]+size[lca]-dis3[u]-dis3[v]+2*dis3[lca];
v1.push_back(ord(n-tans,l));
}
}
col[u]=2;
}
void work4(int cas)
{
v1.clear();
int i,iddd=0,u,v,idddd=0;
for(i=1;i<=idcnt;++i)
v2[i].clear();
for(i=1;i<=n;++i)
f1[i]=-i;
for(i=1;i<=maxn*2;++i)
f2[i]=i;
memset(hash,false,sizeof(hash));
memset(col,0,sizeof(col));
for(i=1;i<=n;++i)
if(hash[i]==false)
{
dfs44(-1,i,++iddd);
}
int k;
scanf("%d",&k);
while(k--)
{
idddd++;
scanf("%d%d",&u,&v);
u++;v++;
if(u==v)
{
v1.push_back(ord(n-1,idddd));
continue;
}
if(f1[u]!=f1[v])
{
v1.push_back(ord(n,idddd));
continue;
}
if(id[u]!=id[v])
{
v2[id[u]].push_back(need(id[v],idddd));
v2[id[v]].push_back(need(id[u],idddd));
continue;
}
if(id[u]==id[v])
{
v1.push_back(ord(n-size[id[u]],idddd));
continue;
}
}
for(i=1;i<=idcnt;++i)
{
if(col[i]==0)
{
tarjan4(-1,i);
}
}
sort(v1.begin(),v1.end(),cmp);
printf("Case #%d:\n",cas);
for(i=0;i<v1.size();++i)
{
printf("%d\n",v1[i].ans);
}
printf("\n");
}
int main()
{
int i,j,u,v,m,cas=0;
while(scanf("%d%d",&n,&m)!=EOF)
{
edgeinit();
while(m--)
{
scanf("%d%d",&u,&v);
u++;v++;
addedge1(u,v);
}
init0();
work1();
work2();
work3();
++cas;
work4(cas);
}
return 0;
}