#树形dp#洛谷 3687 [ZJOI2017]仙人掌
作者:互联网
题目
给定一个简单无向连通图,问有多少种加边方案使得这个图变成简单仙人掌。
分析
首先找到一棵生成树,考虑其它非树边所对应的树的路径上的边最多只能用一次,
这可以用树上差分做,如果一个点到其父节点的边被用了多次就一定无解。
否则没有被用过的部分将形成若干棵树,方案就是它们的乘积。
等于说问用若干条路径覆盖一棵树的方案。
设 \(dp[x]\) 表示以 \(x\) 为根的子树的方案数。
只需要考虑 \(x\) 的邻边如何连接,子树的答案直接相乘。
设 \(f[n]\) 表示 \(n\) 条边任意匹配的方案数,则
\(f[n]=f[n-2]*(n-1)+f[n-1]\)
那么 \(dp[x]*=f[deg[x]]\)
代码
#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=500011,mod=998244353; struct node{int y,next;}e[N<<1],E[N<<1];
int f[N],c[N],v[N],as[N],hs[N],et=1,Et=1,n,dp[N],ans,fat[N],g[N],flag,upd,Lca[N<<1];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline signed getf(int u){return f[u]==u?u:f[u]=getf(f[u]);}
inline void Clear(){
for (rr int i=1;i<=n;++i) c[i]=as[i]=hs[i]=0;
}
inline void dfs1(int x,int fa){
f[x]=x,v[x]=upd,fat[x]=fa;
for (rr int i=as[x];i;i=e[i].next)
if (e[i].y!=fa) dfs1(e[i].y,x),f[e[i].y]=x;
for (rr int i=hs[x];i;i=E[i].next)
if (v[E[i].y]==upd) Lca[i]=Lca[i^1]=getf(E[i].y);
}
inline void dfs2(int x,int fa){
for (rr int i=as[x];i;i=e[i].next)
if (e[i].y!=fa) dfs2(e[i].y,x),c[x]+=c[e[i].y];
}
inline void dfs3(int x,int TOP){
rr int sub=0; dp[x]=1;
for (rr int i=as[x];i;i=e[i].next)
if (e[i].y!=fat[x]){
if (!c[e[i].y]) dfs3(e[i].y,TOP),++sub,dp[x]=1ll*dp[x]*dp[e[i].y]%mod;
else dfs3(e[i].y,e[i].y);
}
if (x==TOP) ans=1ll*ans*dp[x]%mod*g[sub]%mod;
else dp[x]=1ll*dp[x]*g[sub+1]%mod;
}
signed main(){
g[0]=g[1]=1;
for (rr int i=2;i<N;++i) g[i]=(g[i-2]*(i-1ll)+g[i-1])%mod;
for (rr int T=iut();T;--T,putchar(10)){
n=iut(),et=Et=ans=flag=1,++upd;
for (rr int i=1;i<=n;++i) f[i]=i;
for (rr int TOT=iut();TOT;--TOT){
rr int x=iut(),y=iut();
if (getf(x)!=getf(y)){
rr int fa=getf(x),fb=getf(y);
if (fa>fb) fa^=fb,fb^=fa,fa^=fb;
f[fa]=fb;
e[++et]=(node){y,as[x]},as[x]=et;
e[++et]=(node){x,as[y]},as[y]=et;
}else{
E[++Et]=(node){y,hs[x]},hs[x]=Et;
E[++Et]=(node){x,hs[y]},hs[y]=Et;
}
}
dfs1(1,0);
for (rr int i=2;i<=Et;i+=2)
++c[E[i].y],++c[E[i^1].y],c[Lca[i]]-=2;
dfs2(1,0);
for (rr int i=1;i<=n&&flag;++i)
if (c[i]>1) putchar(48),flag=0;
if (!flag) {Clear(); continue;}
dfs3(1,1),print(ans),Clear();
}
return 0;
}
标签:node,洛谷,int,hs,3687,++,ZJOI2017,Et,et 来源: https://www.cnblogs.com/Spare-No-Effort/p/15424224.html