【题解】【BZOJ】AGC008F Blackout
AGC006F Blackout
AGC006F Blackout
1 题外话
什么神仙题目
2 sol
对黑格子\((x,y)\) ,连一条\(x->y\) 的边
此时问题变为如果存在\(x->y,y->z\) 的边,那么添加一条\(z->x\) 的边,最后统计总共有多少条边
现在我们只考虑每个弱连通块怎么统计
尝试对每一个弱连通块三色染色
2.1 无法染色
此时的图中一定有二元环/自环
经过一次操作后二元环能构造出自环,而自环能在若干次操作后将当前弱联通块变为完全图
2.2 不完全染色(用不到第二种或第三种颜色)
此时图中不会出现新边
2.3 染色成功
此时连通块的边数为\(1->2、2->3、3->1\) 的边数总和
3 code
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define int long long using namespace std; const int N=100010; const int M=100010; inline void read(int &x) { x=0; int f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if (ch=='-') { f=-1; } ch=getchar(); } while(ch>='0'&&ch<='9') { x=x*10+ch-'0'; ch=getchar(); } x*=f; } struct note { int t; int next; int val; }; int cnt; int head[N]; note e[M<<1]; inline void add(int x,int y,int val) { e[++cnt].t=y; e[cnt].next=head[x]; e[cnt].val=val; head[x]=cnt; } int n,m; int vis[N]; int f[3],siz; int edg; bool lab; void dfs(int p,int v) { vis[p]=v; f[v]++; siz++; for(int i=head[p];i+1;i=e[i].next) { int t=e[i].t; if (e[i].val==1) { edg++; } if (vis[t]==-1) { dfs(t,(v+e[i].val)%3); } else if (vis[t]!=(vis[p]+e[i].val)%3) { lab=0; } } } int ans; signed main() { read(n),read(m); memset(head,-1,sizeof(head)); for(int i=1;i<=m;i++) { int x,y; read(x),read(y); add(x,y,1); add(y,x,2); } memset(vis,-1,sizeof(vis)); for(int i=1;i<=n;i++) { if (vis[i]==-1) { lab=1; f[0]=f[1]=f[2]=0; siz=edg=0; dfs(i,0); if (lab) { if (min(f[0],min(f[1],f[2]))==0) { ans+=edg; } else { ans+=f[0]*f[1]+f[1]*f[2]+f[2]*f[0]; } } else { ans+=siz*siz; } } } printf("%lld\n",ans); return 0; }
4 注意
打得挺长(
Created: 2021-09-01 周三 20:50