https://codeforces.com/gym/102835/problem/I
比赛的时候想了半天为什么第二个样例不是2个极大边集,最大边集数是3
后来隔壁队告诉我们他们猜想是割边可以也当极大边集,然而他们wa了,于是我也写了一发也wa了
补题的时候发现这个猜想是对的,卧槽他第四种是边数,第三种也是边数,我都当点数算了,一般边双联通分量缩点都是统计点。。。
那么这题就是求割点割边双联通分量水题了
#include<bits/stdc++.h>
using namespace std;
const int maxl=1e6+10;
int n,m,cnt,ind,ans1,ans2,p,q,root,dcc;
int dfn[maxl],low[maxl],ehead[maxl];
int c[maxl],sz[maxl],szed[maxl];
struct ed{int to,nxt,id;}e[maxl<<1];
struct edg
{
int u,v;
}edge[maxl];
bool cutd[maxl],cuted[maxl<<1],vis[maxl<<1];
inline void add(int u,int v,int id)
{
e[++cnt].to=v;e[cnt].id=id;
e[cnt].nxt=ehead[u];ehead[u]=cnt;
}
inline void prework()
{
ind=0;ans1=0,ans2=0,p=0,q=0;cnt=1;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
dfn[i]=low[i]=ehead[i]=0;
cutd[i]=false;
}
for(int i=1;i<=m;i++)
{
cuted[i]=false;
int u,v;scanf("%d%d",&u,&v);
add(u,v,i);add(v,u,i);
edge[i]=edg{u,v};
}
}
inline void tarjand(int u,int fa)
{
dfn[u]=++ind;low[u]=ind;
int son=0,v;
for(int i=ehead[u];i;i=e[i].nxt)
{
v=e[i].to;
if(!dfn[v])
{
tarjand(v,u);
low[u]=min(low[v],low[u]);
if(low[v]>=dfn[u])
{
son++;
if(u!=root || son>1)
cutd[u]=true;
}
}
else
low[u]=min(low[u],dfn[v]);
}
}
inline void tarjaned(int u,int last)
{
dfn[u]=low[u]=++ind;
int v;
for(int i=ehead[u];i;i=e[i].nxt)
{
v=e[i].to;
if(!dfn[v])
{
tarjaned(v,i);
low[u]=min(low[u],low[v]);
if(low[v]>dfn[u])
cuted[e[i].id]=cuted[e[i^1].id]=true;
}
else if(i!=(last^1))
low[u]=min(low[u],dfn[v]);
}
}
inline void dfs(int u)
{
int v;
c[u]=dcc;sz[dcc]++;
for(int i=ehead[u];i;i=e[i].nxt)
{
v=e[i].to;
if(c[v] || cuted[e[i].id]) continue;
dfs(v);
}
}
inline void mainwork()
{
for(int i=1;i<=n;i++)
if(!dfn[i])
{
root=i;
tarjand(i,i);
}
for(int i=1;i<=n;i++)
dfn[i]=low[i]=c[i]=0;
ind=0;
tarjaned(1,0);
dcc=0;
for(int i=1;i<=n;i++)
if(!c[i])
{
++dcc;sz[dcc]=0;szed[dcc]=0;
dfs(i);
}
ans1=0;ans2=0;p=0;q=1;
for(int i=1;i<=n;i++)
if(cutd[i])
++ans1;
for(int i=1;i<=m;i++)
{
if(cuted[i])
++ans2,++p;
if(c[edge[i].u]==c[edge[i].v])
++szed[c[edge[i].u]];
}
for(int i=1;i<=dcc;i++)
{
q=max(szed[i],q);
if(sz[i]>1)
++p;
}
int d=__gcd(p,q);
p/=d;q/=d;
}
inline void print()
{
printf("%d %d %d %d\n",ans1,ans2,p,q);
}
int main()
{
int t;
scanf("%d",&t);
for(int i=1;i<=t;i++)
{
prework();
mainwork();
print();
}
return 0;
}