CF 859 E Desk Disorder - 結論 - 基環樹
阿新 • • 發佈:2018-11-01
題目大意:有若干二元組(a,b),每個二元組可以選擇first或者second。要求選出的數字兩兩不同的方案數。保證a互不相同。
題解:
首先搞出“因為選了第x個二元組的b就導致要選第y個二元組的b”這件事情。顯然因為a兩兩不同所以這構成了一些內向樹或者內向基環樹(有些內向樹的根具有相同的b,此時附加一個超級根合併這些內向樹)。
如果一個點選了b,那麼從這個點出發能夠到達的點都要選b。
什麼時候會gg?如果有兩個點都選了b,並且他們的b是相同的,就gg了。
因此對於內向樹,本質不同的選法有其點數+1個(超級根不算的話,+1表示不選)。對於內向基環樹,不在環上的點是不能選的,選擇了環上的點會使得整個環都被選擇b。因此只要環長大於1就有兩倍的貢獻。乘起來即可。
#include<bits/stdc++.h>
#define gc getchar()
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define mod 1000000007
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
int x,ch;while((ch=gc)<'0'||ch>'9');
x=ch^'0';while((ch=gc)>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0' );return x;
}
const int N=200010;
struct edges{
int to,pre;
}e[N];int h[N],etop,a[N],b[N],ia[N],cnt[N],p[N],vis[N];
inline int add_edge(int u,int v)
{
return e[++etop].to=v,e[etop].pre=h[u],h[u]=etop;
}
int dfs(int x)
{
int c=1;vis[x]=1;
for(int i=h[x],y;i;i=e[i].pre)
if(!vis[y=e[i].to])c+=dfs(y);
return c;
}
int main()
{
int n=inn(),ans=1;
rep(i,1,n) a[i]=inn(),b[i]=inn(),ia[a[i]]=i;
rep(i,1,n) if(ia[b[i]]) p[i]=ia[b[i]];
rep(i,1,n) if(p[i]) add_edge(p[i],i);
rep(i,1,n) if(!p[i]) cnt[b[i]]+=dfs(i);
rep(i,1,2*n) ans=ans*(cnt[i]+1ll)%mod;
rep(i,1,n) if(!vis[i])
{
int x=i;while(!vis[x]) vis[x]=2,x=p[x];
if(vis[x]==2&&x!=p[x]) ans+=ans,(ans>=mod?ans-=mod:0);
for(x=i;vis[x]==2;vis[x]=1,x=p[x]);
}
return !printf("%d\n",ans);
}