求一个联通图的独立集个数(包括空集)
对于树的情况,记 $dp_{u,0/1}$ 为以 $u$ 为根的子树在不选/选 $u$ 时的独立集数量,转移方程是显然的:
$$dp_{u,0}=\prod\limits_{v\in son_u}(dp_{v,0}+dp_{v,1})$$
$$dp_{u,1}=\prod\limits_{v\in son_u}dp_{v,0}$$
注意到非树边很少,所以可以暴力枚举每条边上某个点选/不选,再钦点另一个点的状态,重新算出 DP 值,加起来就可以了。
同时,每次钦点只对该点及其祖先产生影响,所以把这些点拎出来建虚树,虚树上的转移用 DDP 跳链时候的方法维护就可以了。
时间复杂度 $O(nlogn+2^{m-n}(m-n))$。
#include#include #include #define For(i,A,B) for(i=(A);i<=(B);++i) #define fi first #define se second using namespace std; typedef long long ll; const int mod=998244353; const int N=100050; const int BUF=1<<21; char rB[BUF],*rS,*rT; inline char gc(){return rS==rT&&(rT=(rS=rB)+fread(rB,1,BUF,stdin),rS==rT)?EOF:*rS++;} inline int rd(){ char c=gc(); while(c<48||c>57)c=gc(); int x=c&15; for(c=gc();c>=48&&c<=57;c=gc())x=(x<<3)+(x<<1)+(c&15); return x; } int G[N],to[N<<1],nxt[N<<1],sz,g[N],f[18][N],dep[N],dfn[N],dfsc,pa[N],rnk[N],dp[N][2],F[N][2],h[N][2],st[45],sl=-1,r[25]; bool tag[N][2],b[N]; pair<int,int> E[15]; struct mat{ int A[2][2]; mat(){} mat(int a,int b,int c,int d){A[0][0]=a;A[0][1]=b;A[1][0]=c;A[1][1]=d;} inline mat operator*(const mat &b)const{return mat(((ll)A[0][0]*b.A[0][0]+(ll)A[0][1]*b.A[1][0])%mod,((ll)A[0][0]*b.A[0][1]+(ll)A[0][1]*b.A[1][1])%mod,((ll)A[1][0]*b.A[0][0]+(ll)A[1][1]*b.A[1][0])%mod,((ll)A[1][0]*b.A[0][1]+(ll)A[1][1]*b.A[1][1])%mod);} }w[N]; inline bool cmp(int x,int y){return dfn[x]<dfn[y];} int gf(int x){return pa[x]==x?x:pa[x]=gf(pa[x]);} inline void uni(int x,int y){ if(rnk[x] y; else{ if(rnk[x]==rnk[y])++rnk[x]; pa[y]=x; } } inline void adde(int u,int v){ to[++sz]=v;nxt[sz]=G[u];G[u]=sz; to[++sz]=u;nxt[sz]=G[v];G[v]=sz; } void dfs(int u,int fa){ int i,v; dep[u]=dep[f[0][u]=fa]+1; for(i=1;(1<1][f[i-1][u]]; dfn[u]=++dfsc; dp[u][0]=dp[u][1]=1; for(i=G[u];i;i=nxt[i])if((v=to[i])!=fa){ dfs(v,u); dp[u][0]=(ll)dp[u][0]*(dp[v][0]+dp[v][1])%mod; dp[u][1]=(ll)dp[u][1]*dp[v][0]%mod; } } inline int lca(int u,int v){ short i; if(dep[u]<dep[v])swap(u,v); for(i=16;i>=0;--i)if(dep[u]-(1<=dep[v])u=f[i][u]; if(u==v)return u; for(i=16;i>=0;--i)if(f[i][u]!=f[i][v]){u=f[i][u];v=f[i][v];} return f[0][u]; } inline void linke(int u,int v){ int fa,i,tp,t1,t2,tv=v; to[++sz]=v;nxt[sz]=g[u];g[u]=sz; w[v]=mat(1,0,0,1); for(;(fa=f[0][tv])!=u;tv=fa){ for(i=G[fa],t1=t2=1;i;i=nxt[i])if((tp=to[i])!=f[0][fa]&&tp!=tv){t1=(ll)t1*(dp[tp][0]+dp[tp][1])%mod;t2=(ll)t2*dp[tp][0]%mod;} w[v]=mat(t1,t1,t2,0)*w[v]; } b[tv]=1; } inline void ins(int u){ int l=lca(st[sl],u); if(l!=st[sl]){ for(;sl&&dep[st[sl-1]]>=dep[l];--sl)linke(st[sl-1],st[sl]); if(st[sl]!=l){ linke(l,st[sl]); st[sl]=l; } } st[++sl]=u; } void Dfs(int u){ int i,v; h[u][0]=h[u][1]=1; for(i=g[u];i;i=nxt[i])Dfs(to[i]); for(i=G[u];i;i=nxt[i])if((v=to[i])!=f[0][u]&&!b[v]){h[u][0]=(ll)h[u][0]*(dp[v][0]+dp[v][1])%mod;h[u][1]=(ll)h[u][1]*dp[v][0]%mod;} } void Dp(int u){ int i,v,s0=tag[u][0]?0:h[u][0],s1=tag[u][1]?0:h[u][1]; for(i=g[u];i;i=nxt[i]){ Dp(v=to[i]); s0=(ll)s0*(F[v][0]+F[v][1])%mod;s1=(ll)s1*F[v][0]%mod; } F[u][0]=((ll)s0*w[u].A[0][0]+(ll)s1*w[u].A[0][1])%mod; F[u][1]=((ll)s0*w[u].A[1][0]+(ll)s1*w[u].A[1][1])%mod; } int main(){ int n=rd(),m=rd(),i,u,v,x,y,S,cnt=0,tot=0,ans=0; For(i,1,n)pa[i]=i; For(i,1,m){ x=gf(u=rd());y=gf(v=rd()); if(x!=y){ adde(u,v); uni(x,y); }else{ E[cnt].fi=u;E[cnt++].se=v; r[tot++]=u;r[tot++]=v; } } dfs(1,0); if(!cnt){ printf("%d",(dp[1][0]+dp[1][1])%mod); return 0; } sort(r,r+tot,cmp);tot=unique(r,r+tot)-r; st[sl=0]=1; if(r[0]!=1)ins(r[0]); For(i,1,tot-1)ins(r[i]); for(;sl;--sl)linke(st[sl-1],st[sl]); w[1].A[0][0]=w[1].A[1][1]=1; Dfs(1); For(S,0,(1< 1){ For(i,0,cnt-1)if((S>>i)&1){tag[E[i].fi][0]=1;tag[E[i].se][1]=1;} else tag[E[i].fi][1]=1; Dp(1); ans=((ll)ans+F[1][0]+F[1][1])%mod; For(i,0,cnt-1)tag[E[i].fi][0]=tag[E[i].fi][1]=tag[E[i].se][0]=tag[E[i].se][1]=0; } printf("%d",ans); return 0; }