1. 程式人生 > >CF 859 E Desk Disorder - 結論 - 基環樹

CF 859 E Desk Disorder - 結論 - 基環樹

題目大意:有若干二元組(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); }