[agc006f]Blackout

来源:互联网 发布:数据库设计实例 编辑:程序博客网 时间:2024/06/09 21:17

题目大意

给你一个人有向图。
如果x->y,y->z,加上z->x。
重复该过程直到不能再添加。
求最终图中有多少边。

做法

每一个弱联通块独立。
尝试对一个弱联通块三染色,然后分为三种情况。
1、染色失败。
一定是出现了二元环或自环,此时所有边均会出现。
2、染色不完全(没有用完三种颜色)。
此时不会出现新的边。
3、染色成功。
所有染色为0的向1连,1向2,2向0。

#include<cstdio>#include<algorithm>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;typedef long long ll;const int maxn=100000+10;int h[maxn],go[maxn*2],dis[maxn*2],nxt[maxn*2],fa[maxn],co[maxn];bool bz[maxn],pd[maxn];int i,j,k,l,t,n,m,tot,top,cnt,zero,one,two,mx;bool czy;ll ans;void add(int x,int y,int z){    go[++tot]=y;    dis[tot]=z;    nxt[tot]=h[x];    h[x]=tot;}void dfs(int x){    bz[x]=1;    top++;    if (!co[x]) zero++;    else if (co[x]==1) one++;    else two++;    mx=max(mx,co[x]);    int t=h[x];    while (t){        if (!pd[(t+1)/2]){            pd[(t+1)/2]=1;            cnt++;            if (!bz[go[t]]){                co[go[t]]=(co[x]+dis[t]+3)%3;                dfs(go[t]);            }            else{                if (co[go[t]]!=(co[x]+dis[t]+3)%3) czy=1;            }        }        t=nxt[t];    }}int main(){    scanf("%d%d",&n,&m);    fo(i,1,m){        scanf("%d%d",&j,&k);        add(j,k,1);add(k,j,-1);    }    fo(i,1,n)        if (!bz[i]){            czy=top=zero=one=two=cnt=mx=0;            dfs(i);            if (czy){                ans+=(ll)top*top;                continue;            }            if (!zero||!one||!two){                ans+=(ll)cnt;                continue;            }            ans+=(ll)zero*one;            ans+=(ll)one*two;            ans+=(ll)two*zero;        }    printf("%lld\n",ans);}
原创粉丝点击