【CF711D】Directed Roads
题目大意:给定一个 N 个点,N 条边的无向图,现给每条边定向,求有多少种定向方式使得定向后的有向图中无环。
题解:显然,这是一个外向树森林,定向后存在环的情况只能发生在基环树中环的位置,环分成顺时针和逆时针两种情况,其他边方向随意。因此,记外向树森林中环的大小为 \(w[i]\),则答案为$$2^{n-\sum w[i]}*\prod (2^{w[i]}-2)$$
代码如下
#include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define all(x) x.begin(),x.end()
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const int maxn=2e5+10;
inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
inline ll sqr(ll x){return x*x;}
inline ll read(){
ll x=0,f=1;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch));
return f*x;
}
vector<P> G[maxn];int tot=1;
int n,m,dep[maxn],vis[maxn];
ll ans=1,p[maxn];
void read_and_parse(){
n=m=read(),p[0]=1;
for(int i=1;i<=n;i++)p[i]=p[i-1]*2%mod;
for(int i=1,to;i<=n;i++)to=read(),G[i].pb(mp(to,++tot)),G[to].pb(mp(i,++tot));
}
void dfs(int u,int fe){
vis[u]=1;
for(int i=0;i<G[u].size();i++){
int v=G[u][i].first,e=G[u][i].second;if(fe==(e^1))continue;
if(!vis[v])dep[v]=dep[u]+1,dfs(v,e);
else if(vis[v]==1)m-=dep[u]-dep[v]+1,ans=ans*(p[dep[u]-dep[v]+1]-2)%mod;
}
vis[u]=2;
}
void solve(){
for(int i=1;i<=n;i++)if(!vis[i])dfs(i,0);
ans=ans*p[m]%mod;
printf("%lld\n",ans);
}
int main(){
read_and_parse();
solve();
return 0;
}