关键
这种有因果关系的,确实是用图论,但是我是想用topo
最后连边失败
这里是分成多个连通块,每个连通块的点数必须和边数相同
而且如果已经算过贡献,就不在重复计算了
代码
//每一个环的点数和边数都必须要相同
//如果这个环已经乘过贡献了,那就不在次计算贡献,直接标记为1就可以了
//用并查集来统计连通块的点和边
//两个点一条边就可以了
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int M=1e5+5;
const int mod=998244353;
int a[M],b[M];;
int siz[M],cnt[M];
bool st[M];
int fa[M];
int find(int x) {
return x==fa[x]?fa[x]:fa[x]=find(fa[x]);
}
signed main() {
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int TT;cin>>TT;
while(TT--) {
int n;cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)cin>>b[i];
for(int i=1;i<=n;i++)cnt[i]=st[i]=0,fa[i]=i,siz[i]=1;
int ans=1;
for(int i=1;i<=n;i++) {
if(a[i]==b[i])st[a[i]]=1,ans=ans*n%mod;//自环的环,标记已成乘过了
cnt[a[i]]++;
fa[find(a[i])]=find(b[i]);
}
for(int i=1;i<=n;i++)
if(find(i)!=i)cnt[find(i)]+=cnt[i],st[find(i)]|=st[i],siz[find(i)]++;
//吧孩子的状态进行统计
for(int i=1;i<=n;i++)
if(find(i)==i) {
if(cnt[i]!=siz[i])ans=0;//点数和边数不相同
if(st[i]==0)ans=ans*2%mod;
}
cout<<ans<<endl;
}
return 0;
}
//当时是想着有些点是已经连了,然后把已经连过的相关的点又进行连接,模拟起来确实有些复杂
//正确性也不得而知,虽然感觉思路没啥问题
//但是还是需要简化模拟吧
标签:连通,新年,fa,--,TT,CF,cin,int
From: https://www.cnblogs.com/basicecho/p/17017912.html