abc226E - Just one
怎么感觉大家都这么懂啊。
结论就是基环森林才有解
证明的话大概是这样
首先不是同一个连通块的话则互不相干,分开讨论即可。
如果一个点的度为1,那么它的出边唯一确定,那么我们可以删去这些点,删去的同时会造成一些新的点度为1,不断扩展即可,同时注意判断无解情况,有点类似于拓扑排序的一个BFS。
那么我们现在假定剩下的点的度都大于等于2,假如不是构成一个环,我们给其中一条边定向\((x->y)\),那么其他与这个点相连的边也确定了方向,必然是指向
\(z->x (z \neq y)\),由于每个点的度大于等于2,则每个点z,也必然存在w,使得\((w->z)\),并且它不会构成一个环,那么点数是无穷大的。
所以必然是一个环的形式,并且是一个简单环。
对于一个环,只看这个环,每个点,一定是一条边近,一条边出,因为进出相等,如果存在一个点两条边都是入,则必然存在一个点会有两条出边。那么我们确定了环上边的方向之后,如果还有别的边,是一定会造成矛盾的,会使这条边上的一点出度大于1。
因此一定是简单环,且方案只有两种。
所以判断下是不是基环森林,然后算联通块个数即可。
#include<cstdio>
#include<algorithm>
#include<set>
#include<queue>
#include<cstring>
#define fo(i,a,b) for (int (i)=(a);(i)<=(b);(i)++) //
#define fd(i,b,a) for (int (i)=(b);(i)>=(a);(i)--)
#define mk(x,y) make_pair((x),(y))
#define A puts("YES")
#define B puts("NO")
using namespace std;
typedef double db;
typedef long long ll;
const int N=2e5+5;
const ll mo=998244353;
int head[N],to[N*2],nex[N*2],tot,d[N];
bool vis[N],bz[N],del[N];
int n,m,x,y;
queue<int> q;
void add(int x,int y){
to[++tot]=y; nex[tot]=head[x]; head[x]=tot;
}
void dfs(int x,int y){
bz[x]=1;
for (int i=head[x];i;i=nex[i]){
int v=to[i];
if (bz[v]) continue;
dfs(v,x);
}
}
int main()
{
// freopen("data.in","r",stdin);
scanf("%d %d",&n,&m);
fo(i,1,m){
scanf("%d %d",&x,&y);
add(x,y); add(y,x);
d[x]++;
d[y]++;
}
bool flag=1;
fo(i,1,n) {
if (!d[i]) flag=0;
if (d[i]==1) q.push(i),vis[i]=1;
}
if (!flag) {
puts("0");
return 0;
}
while (!q.empty()) {
x=q.front(); q.pop();
del[x]=1;
if (!d[x]) {
flag=0;
break;
}
for (int i=head[x];i;i=nex[i]){
int v=to[i];
if (del[v]) continue;
d[v]--;
if (d[v]==1) {
vis[v]=1;
q.push(v);
}
}
}
fo(i,1,n) if (!d[i] || d[i]>2) flag=0;
if (!flag) {
puts("0");
return 0;
}
ll ans=1;
fo(i,1,n){
if (!bz[i]) {
dfs(i,0);
ans=ans*2ll%mo;
}
}
printf("%lld",ans);
return 0;
}