其实挺简单的但是没想出来…………
首先判断无解情况,即,一开始的图就不是仙人掌,使用tarjan判断如果一个点dfs下去有超过一个点比他早,则说明存在非简单环。 然后考虑dp,显然原图中已经属于某个简单环的边就是没用的,tarjan缩点之后删掉两个端点在一个强连通分量中的边。(无向图的tarjan要记录father防止往回走,instack数组不需要了。 现在图变成了一个森林。 然后设sum为某个点的子树个数,w[i]为i棵子树相互连成环的方案数,w[i]=w[i-1]+w[i-2]*(i-1);g[i]为第i个点(i不是根)的方案数,g[u]=f[u]*w[sum]+f[u]*w[sum-1]*sum;f[i]为第i个点(i是根)的方案数f[u]=f[u]*w[sum] 依次树形dp,把答案乘起来即可。#include#include #include using namespace std;const int N=500005,mod=998244353;int T,n,m,h[N],cnt,f[N],w[N],g[N],dfn[N],tot,low[N],bl[N],col,s[N],top;bool v[N],fl;long long ans;struct qwe{ int ne,to;}e[N*10];int read(){ int r=0,f=1; char p=getchar(); while(p>'9'||p<'0') { if(p=='-') f=-1; p=getchar(); } while(p>='0'&&p<='9') { r=r*10+p-48; p=getchar(); } return r*f;}void add(int u,int v){ cnt++; e[cnt].ne=h[u]; e[cnt].to=v; h[u]=cnt;}void tarjan(int u,int fa) { dfn[u]=low[u]=++tot; s[++top]=u; bool flag=0; for(int i=h[u];i;i=e[i].ne) if(e[i].to!=fa) { if(!dfn[e[i].to]) { tarjan(e[i].to,u); low[u]=min(low[u],low[e[i].to]); if(low[e[i].to]