之前写过这个题的题解,但是做法非常麻烦,今天看frog的博客的时候,突发灵感,把这题改了改,代码从280行降到了193,过掉了,而且想法也简单了很多。
之前的题解传送门:http://blog.csdn.net/qian99/article/details/9811501
frog的博文传送门:http://blog.csdn.net/frog1902/article/details/10051323#comments
可以先看看frog题解的那道题,虽说那个是有向图,仙人掌图的定义和本题也有些不同,不过还是有启发性意义的。
这道题中Cactus的定义有两个要求,一个是连通图,另一个是每条边至多在一个简单环中。第一个好说,就不说了……对于第二条,考虑dfs的过程,每当lowv<pre[u]或者pre[v]<pre[u]的时候,就说明u有一个子节点有一条路径连向了u的父节点,这样的话肯定会存在一个环,如果这种情况发生大于等于两次,那么就说明u连向其祖先的边不只在一个简单环中,那么这个图肯定不是Cactus。至于仙人掌度的求法就不说了吧,可以看上一篇题解。
代码:
#include <iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#define inf 2139062143
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=20000+10;
struct Edge
{
int u,v;
};
vector<int>G[maxn],bcc[maxn];
int pre[maxn],bccno[maxn],dfs_clock,bcc_cnt;
int parents[maxn],sum;
bool flag;
stack<Edge>S;
struct BigInt
{
int num[7000];
int len;
void clear()
{
for(int i=0;i<7000;++i) num[i]=0;
len=0;
}
void getBigInt(ll n)
{
clear();
if(n==0) num[len++]=0;
while(n!=0)
{
num[len++]=n%10;
n/=10;
}
}
void getBigInt(int n)
{
ll m=(ll)n;
getBigInt(m);
}
BigInt operator * (const BigInt a) const
{
int m=a.len;
int n=len;
BigInt c;
c.clear();
int bs=0,w=0,jinwei=0,tp;
for(int i=0;i<m;++i)
{
jinwei=0;
w=0;
for(int j=0;j<n;++j)
{
tp=a.num[i]*num[j]+jinwei+c.num[bs+w];
c.num[bs+w]=tp%10;
jinwei=tp/10;
w++;
}
while(jinwei!=0)
{
c.num[bs+w]=jinwei%10;
jinwei/=10;
w++;
}
c.len=max(c.len,bs+w);
bs++;
}
return c;
}
};
int Find(int x)
{
return x==parents[x]?parents[x]:parents[x]=Find(parents[x]);
}
void Uion(int x,int y)
{
int a=Find(x);
int b=Find(y);
if(a!=b)
{
sum++;
parents[b]=a;
}
}
int dfs(int u,int fa)
{
int cnt=0;
int lowu=pre[u]=++dfs_clock;
for(int i=0;i<G[u].size();++i)
{
int v=G[u][i];
Edge e=(Edge){u,v};
if(!pre[v])
{
S.push(e);
int lowv=dfs(v,u);
lowu=min(lowu,lowv);
if(lowv<pre[u])
cnt++;
if(lowv>=pre[u])
{
bcc_cnt++;bcc[bcc_cnt].clear();
while(true)
{
Edge x=S.top();S.pop();
if(bccno[x.u]!=bcc_cnt){bcc[bcc_cnt].push_back(x.u);bccno[x.u]=bcc_cnt;}
if(bccno[x.v]!=bcc_cnt){bcc[bcc_cnt].push_back(x.v);bccno[x.v]=bcc_cnt;}
if(x.u==u&&x.v==v) break;
}
}
}
else if(pre[v]<pre[u]&&v!=fa)
{
cnt++;
S.push(e);
lowu=min(lowu,pre[v]);
}
}
if(cnt>=2) flag=false;
return lowu;
}
void find_bcc(int n)
{
memset(pre,0,sizeof(pre));
memset(bccno,0,sizeof(bccno));
dfs_clock=bcc_cnt=0;
dfs(1,-1);
}
BigInt slove(int n)
{
BigInt ans;
ans.getBigInt(0);
flag=true;
find_bcc(n);
if(!flag) return ans;
ans.getBigInt(1);
BigInt tmp;
for(int i=1;i<=bcc_cnt;++i)
{
int z=bcc[i].size();
tmp.getBigInt(z+1);
if(z>=3)
ans=ans*tmp;
}
return ans;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n,m,k,tcase=0;
while(~scanf("%d%d",&n,&m))
{
if(tcase++) printf("\n");
int a,b;
for(int i=0;i<=n;++i)
{
parents[i]=i;
G[i].clear();
}
sum=0;
while(m--)
{
scanf("%d",&k);
scanf("%d",&a);
for(int i=1;i<k;++i)
{
scanf("%d",&b);
G[a].push_back(b);
G[b].push_back(a);
Uion(a,b);
a=b;
}
}
BigInt ans;
if(sum+1!=n) ans.getBigInt(0);
else ans=slove(n);
for(int i=ans.len-1;i>=0;--i)
printf("%d",ans.num[i]);
printf("\n");
}
return 0;
}