AT2167 [AGC006F] Blackout
Description
縦、横ともに $ N $ マスのマス目があります。 上から $ i $ マス目、左から $ j $ マス目のマスを ( $ i $ , $ j $ ) と表します。
最初、 $ M $ 個のマスが黒く塗られており、それ以外のマスはすべて白です。 具体的には、マス ( $ a_1 $ , $ b_1 $ ), ( $ a_2 $ , $ b_2 $ ), $ ... $ , ( $ a_M $ , $ b_M $ ) が黒く塗られています。
すぬけ君は次のルールに従い、可能な限りマスを黒く塗っていきます。
- ある $ 1\ \leq\ x,y,z\ \leq\ N $ について、マス ( $ x $ , $ y $ ), ( $ y $ , $ z $ ) がともに黒で、マス ( $ z $ , $ x $ ) が白ならば、マス ( $ z $ , $ x $ ) を黒く塗る。
すぬけ君が可能な限りマスを黒く塗ったとき、最終的に黒いマスは何個になるかを求めてください。
Solution
发现按照题意描述可以画出一个三元环,于是把每个黑色视为一条连边,在图上用三种颜色循环染色
如果没有将三种颜色用完,不能画出新的边,答案为边数
如果不能正确染色,那么将会形成一个完全图,答案为点数的平方
如果可以正确染色,所有相邻颜色都会连边,分三类计算
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> using namespace std; int n,m,head[100005],tot,col[100005],cnt[3],siz,num; long long ans; bool tag; struct Edge { int to,nxt,w; }edge[200005]; inline int read() { int f=1,w=0; char ch=0; while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9') w=(w<<1)+(w<<3)+ch-'0',ch=getchar(); return f*w; } void dfs(int k,int c) { col[k]=c+1,cnt[c]++,siz++; for(int i=head[k];i;i=edge[i].nxt) { int v=edge[i].to; if(edge[i].w==1) num++; if(!col[v]) dfs(v,(c+edge[i].w+3)%3); else if(col[v]!=(c+edge[i].w+3)%3+1) tag=true; } } int main() { n=read(),m=read(); for(int i=1;i<=m;i++) { int u=read(),v=read(); edge[++tot]=(Edge){v,head[u],1},head[u]=tot,edge[++tot]=(Edge){u,head[v],-1},head[v]=tot; } for(int i=1;i<=n;i++) { if(!col[i]) { tag=false,cnt[0]=cnt[1]=cnt[2]=siz=num=0; dfs(i,0); if(tag) ans+=1ll*siz*siz; else if(!cnt[2]||!cnt[1]||!cnt[0]) ans+=1ll*num; else ans+=1ll*cnt[0]*cnt[1]+1ll*cnt[0]*cnt[2]+1ll*cnt[1]*cnt[2]; } } printf("%lld\n",ans); retu