【Luogu】 [AGC006F] Blackout

题目链接

Atcoder方向
Luogu方向

题目解法

考虑简化问题
( x , y ) (x,y) (x,y) 是黑点,则从 x − > y x->y x>y 连一条边
这样将问题转化成了对于 x − > y − > z x->y->z x>y>z 的路径,必须连 z − > x z->x z>x,答案就是边的个数

我们可以把 x − > y x->y x>y 类似成无向边,然后对于无向图的连通块,三染色
给出结论:

  1. 若可以三染色,且颜色个数 < 3 <3 <3,则不会新增边
    证明:若会新增边,则必有 x − > y − > z x->y->z x>y>z 的路径,那么一定会染 3 种颜色

  2. 若可以三染色,且颜色个数 = 3 =3 =3,令颜色 x x x s x s_x sx 个,则最终边数为 s 0 s 1 + s 1 s 2 + s 2 s 0 s_0s_1+s_1s_2+s_2s_0 s0s1+s1s2+s2s0
    证明:考虑数学归纳法
    若当前图是满足结论的,考虑新增加一个与当前图连通的点 y y y,那么必有当前图内的一点 x x x x − > y x->y x>y 的边(即使是反向边只要设权为 -1 即可,这里只考虑正向边)
    y y y 的颜色为 1,则 x x x 的颜色为 0
    z − > x − > y z->x->y z>x>y z z z 的颜色为 2,所以 y y y 必定连向所有颜色为 2 的点,所以颜色 1 − > 2 1->2 1>2 得证
    同理有 x − > y − > z x->y->z x>y>z 的边,所以 0 − > 1 0->1 0>1 得证
    2 − > 0 2->0 2>0 x x x 无关,所以得证

  3. 若无法三染色,则最终状态是完全图
    令点数为 n n n,则最终边数为 n 2 n^2 n2
    证明:首先所有点都会有一条连向自己的边,证明的话考虑无法三染色,必有 x − > y x->y x>y,且 x , y x,y x,y 颜色相同
    上面的结论就易证所有点都会互相连边

#include 
#define int long long
using namespace std;
const int N=100100;
int n,m,col[N],nodes,lines,cnt[3];
int e[N<<1],h[N],ne[N<<1],w[N<<1],idx;
bool flg,vis[N];
inline int read(){
	int FF=0,RR=1;
	char ch=getchar();
	for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
	for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
	return FF*RR;
}
void add(int x,int y,int z){ e[idx]=y,w[idx]=z,ne[idx]=h[x],h[x]=idx++;}
void dfs(int u){
	vis[u]=1,nodes++,cnt[col[u]]++;
	for(int i=h[u];~i;i=ne[i]){
		int v=e[i],necol=(col[u]+w[i]+3)%3;
		lines++;
		if(vis[v]){
			if(col[v]!=necol) flg=1;
			continue;
		}
		col[v]=necol;
		dfs(v);
	}
}
signed main(){
	n=read(),m=read();
    memset(h,-1,sizeof(h));
	for(int i=1;i<=m;i++){
		int x=read(),y=read();
		add(x,y,1),add(y,x,-1);
	}
	int ans=0;
	for(int i=1;i<=n;i++) if(!vis[i]){
		cnt[0]=cnt[1]=cnt[2]=0;
		flg=nodes=lines=0,dfs(i);
        // cout<
		if(flg) ans+=nodes*nodes;
		else if((cnt[0]>0)+(cnt[1]>0)+(cnt[2]>0)<3) ans+=lines/2;
		else ans+=cnt[0]*cnt[1]+cnt[1]*cnt[2]+cnt[2]*cnt[0];
	}
	printf("%lld",ans);
	return 0;
}

你可能感兴趣的:(Atcoder,算法)