[ZJOI2017]仙人掌
题面
分析
如果本来就不是仙人掌那就凉啦
特判仙人掌的话
先dfs建树建fa
然后对于每一条边 从它dfn大的那个点开始跳fa
把跳过的边打标记
显然有环的话 环上的边会被跳两次
如果一个边被多个环覆盖 那么标记也会打两次以上
然后显然连边的时候 选取的路径上的边都不能被环覆盖过
所以原图就被环切成了很多树
对于每一个树 考虑dp
dp方式参考orz
最后的式子
\(f[u]=\prod g[v] \times h[num]\)
\(g[u]=f[u]+\prod g[v] \times h[num-1] \times num\)
多数据注意初始化复杂度!
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e5 + 5;
const ll P = 998244353;
const int inf = 0x3f3f3f3f;
struct Edge{int v, next;}edge[N << 2];
int head[N], esize;
inline void addedge(int x, int y){
edge[++esize] = (Edge){y, head[x]}, head[x] = esize;
}
int n, m, fa[N], dfn[N], tag[N], a[N], dfncnt; ll ans, h[N], g[N], f[N];
inline bool rule(int x, int y){return dfn[x] < dfn[y];}
inline void init(){
if(n){
for(int i = 1; i <= n; ++i) head[i] = -1, tag[i] = dfn[i] = fa[i] = 0;
}
else {
memset(head, -1, sizeof(head)), memset(tag, 0, sizeof(tag)),
memset(dfn, 0, sizeof(dfn)), memset(fa, 0, sizeof(fa));
}
esize = 1, dfncnt = 0, ans = 1;
}
void dfs(int x, int ff){
dfn[x] = ++dfncnt, fa[x] = ff;
for(int i = head[x], vv; ~i; i = edge[i].next)
if(!dfn[edge[i].v]) dfs(edge[i].v, x);
}
void update(int x){
ll son = 0, gsum = 1; f[x] = 1, tag[x] = -1;
for(int i = head[x], vv; ~i; i = edge[i].next){
vv = edge[i].v; if(tag[vv] != 1 || vv == fa[x]) continue;
update(vv); ++son, gsum = gsum * g[vv] % P;
}
f[x] = gsum * h[son] % P, g[x] = (f[x] + gsum * h[son - 1] % P * son % P) % P;
// printf("%d %lld %lld\n", x, f[x], g[x]);
}
int main(){
int T; scanf("%d", &T);
h[1] = h[0] = 1, h[2] = 2;
for(int i = 3; i <= 5e5; ++i) h[i] = (h[i - 1] + h[i - 2] * (i - 1) % P) % P;
while(T--){
init();
scanf("%d%d", &n, &m);
for(int i = 1, x, y; i <= m; ++i)
scanf("%d%d", &x, &y), addedge(x, y), addedge(y, x);
dfs(1, 0); bool flag = 0;
for(int i = 2, uu, vv; i <= esize; i += 2){
uu = edge[i ^ 1].v, vv = edge[i].v;
if(dfn[uu] < dfn[vv]) swap(uu, vv);
while(uu != vv){
++tag[uu];
if(tag[uu] > 2) {flag = 1; break;}
uu = fa[uu];
}
if(flag) break;
}
if(flag){printf("0\n"); continue;}
for(int i = 1; i <= n; ++i) a[i] = i;
sort(a + 1, a + n + 1, rule);
for(int i = 1; i <= n; ++i) if(~tag[a[i]]){
update(a[i]); ans = ans * f[a[i]] % P;
}
printf("%lld\n", ans);
}
return 0;
}