(多校)仙人掌(cactus)

(点强连通)
如图两种情况:
image

这到题其实就是在 \(tarjan\)\(dp\)

先观察题意,构造一下最终的匹配图

容易发现,要么是环,要么是单边,使得每个联通块没有交集,但集合的并为总点集

我们令 \(dp_{i,0/1}\) 表示是否选 \(i\) 点,各自对应的贡献

对于一个环,可以选环,也可以断环选边

环的贡献为 \(2*(-1)^{cnt-1}\) ,边的贡献为 \((-1)\)

对于仙人掌上的点强连通,如果是单边的话直接转移即可
如果是环的话,选环的情况直接转移,另一种情况需要再在环上 \(dp\) 一遍

Code
#include <bits/stdc++.h>
#define re register
#define int long long
#define ll long long
// #define lls long long
#define pir make_pair
#define fr first 
#define sc second
#define db double
using namespace std;
const int mol=993244853;
const int maxn=1e7+10;
const int INF=1e9+10;
inline int qpow(int a,int b) { int ans=1; while(b) { if(b&1) (ans*=a)%=mol; (a*=a)%=mol; b>>=1; } return (ans+mol)%mol; }
inline int read() {
    int s=0,w=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { s=s*10+ch-'0'; ch=getchar(); }
    return s*w;
}

int n,m,q[maxn],du[maxn],f[maxn][2],dp[maxn][2];
struct EDGE { int var,nxt; } edge[maxn<<1];
int cnt,head[maxn];
inline void add(int a,int b) { edge[++cnt]=(EDGE){ b,head[a] }; head[a]=cnt; }
int tot,dfn[maxn],low[maxn]; int top,sta[maxn];
inline void ad(int &x) { x= x>=mol? x-mol:x; }
inline void tarjan(int now,int fa) {
	dfn[now]=low[now]=++tot; sta[++top]=now;
	dp[now][1]=0; dp[now][0]=1;
	for(re int i=head[now],to;i;i=edge[i].nxt) if((to=edge[i].var)!=fa) {
		if(!dfn[to]) {
			tarjan(to,now);
			if(low[to]>=low[now]) {
				int ls=0; q[ls=1]=now;
				while(sta[top+1]!=to) { q[++ls]=sta[top--]; }
				if(ls==2) { 
					(dp[now][1]=(mol+ dp[now][1]*dp[q[2]][1]%mol- dp[now][0]*dp[q[2]][0]%mol )%mol)%=mol;
					(dp[now][0]*=dp[q[2]][1])%=mol; 
					continue; 
				}
				int ls1=2ll*qpow(-1,ls-1)%mol,ls0=0; 
				for(re int i=1;i<=ls;i++) (ls1*=dp[q[i]][0])%=mol; 
				f[q[2]][1]=dp[q[2]][1]; f[q[2]][0]=dp[q[2]][0];
				for(re int i=3;i<=ls;i++) {
					int a=q[i],pre=q[i-1];
					f[a][0]=f[pre][1]*dp[a][0]%mol; 
					f[a][1]=(mol+ f[pre][1]*dp[a][1]%mol - f[pre][0]*dp[a][0]%mol )%mol;
				}  
				(ls0+= dp[now][0]*f[q[ls]][1]%mol )%=mol;
				(ls1+= mol -dp[now][0]*f[q[ls]][0]%mol )%=mol;
				f[q[1]][1]=dp[q[1]][1]; f[q[1]][0]=dp[q[1]][0];
				for(re int i=2;i<=ls;i++) {
					int a=q[i],pre=q[i-1];
					f[a][0]=f[pre][1]*dp[a][0]%mol; 
					f[a][1]=(mol+ f[pre][1]*dp[a][1]%mol - f[pre][0]*dp[a][0]%mol )%mol;
				}
				(ls1+=f[q[ls]][1])%=mol;
				dp[now][1]=ls1; dp[now][0]=ls0;
			} 
			low[now]=min(low[now],low[to]);
		} else { low[now]=min(low[now],dfn[to]); }
	}
}
signed main(void) {
	freopen("erp.in","r",stdin); freopen("erp.out","w",stdout);
	n=read(); m=read();
	for(re int i=1,a,b;i<=m;i++) { a=read(); b=read(); add(a,b); add(b,a); ++du[a]; ++du[b]; }
	tarjan(1,0);
	printf("%lld\n",(dp[1][1]%mol+mol)%mol); 
}
posted @ 2021-11-03 09:55  zJx-Lm  阅读(196)  评论(0编辑  收藏  举报