[agc006f]blackout

题意:

给你一个$n\times n$的网格,开始有$m$个被涂成黑色的格子,如果存在三个格子$(x,y)$,$(y,z)$,$(z,x)$满足$(x,y)$,$(y,z)$均为黑格子且$(z,x)$为白格子,那么就将$(z,x)$涂黑,问最后会有多少个被涂黑的格子。

题解:

神仙题。。。感觉正解比C题还神仙。。。

用矩阵直接构造非常麻烦,矩阵甚至构造不出来,那么可以考虑对每个黑格子$(x,y)$,从$x$向$y$连边,那么问题就转化到了有向图上。(真是让人只能跪地膜的构造,场上完全没这样想过。。。)这样整个矩阵就变成了一个邻接矩阵,题意就变成了如果图中有两条边$<x,y>$,$<y,z>$,那么就连一条边$<z,x>$;

显然每个弱联通块之间没有关系,所以每个联通块单独考虑。大(sui)胆(bian)证(shou)明(wan)之后可以发现几个性质:

1.一条长度为2的链会变成一个三元环;

2.一个二元环会形成一个自环;

3.只要形成自环,那么整个联通块就会变成一个完全图

所以考虑判断这个联通块有没有自环or二元环,这个有固定技巧,即将原图三染色(012染色),然后分类讨论:

1.如果染色失败(即颜色冲突),那么说明联通块中出现了自环或二元环,变成了完全图,那么直接把边数平方即可;

2.如果三种颜色没有全部出现,说明图中没有长度大于一的链,此时不会出现新的边,即不会出现新格子;

3.如果染色成功且三种颜色都出现了,那么答案就是0的点向1的连边,1的点向2的连边,2的点向3的连边,直接乘起来即可;

代码:

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<cmath>
 6 using namespace std;
 7 typedef long long ll;
 8 struct edge{
 9     int v,w,next;
10 }a[500001];
11 int n,m,u,v,c[3],cnt,_cnt,cc[500001],tot=0,head[500001];
12 bool used[500001],ok;
13 ll ans=0;
14 void add(int u,int v,int w){
15     a[++tot].v=v;
16     a[tot].w=w;
17     a[tot].next=head[u];
18     head[u]=tot;
19 }
20 void dfs(int u){
21     c[cc[u]]++;
22     used[u]=true;
23     cnt++;
24     for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
25         int v=a[tmp].v;
26         if(a[tmp].w==1)_cnt++;
27         if(!used[v]){
28             cc[v]=(cc[u]+a[tmp].w+3)%3;
29             dfs(v);
30         }else if(cc[v]!=(cc[u]+a[tmp].w+3)%3)ok=false;
31     }
32 }
33 int main(){
34     memset(head,-1,sizeof(head));
35     memset(cc,-1,sizeof(cc));
36     memset(used,0,sizeof(used));
37     scanf("%d%d",&n,&m);
38     for(int i=1;i<=m;i++){
39         scanf("%d%d",&u,&v);
40         add(u,v,1);
41         add(v,u,-1);
42     }
43     for(int i=1;i<=n;i++){
44         if(!used[i]){
45             c[0]=c[1]=c[2]=cnt=_cnt=0;
46             ok=1;
47             cc[i]=0;
48             dfs(i);
49             if(!ok)ans+=(ll)cnt*cnt;
50             else if(c[0]&&c[1]&&c[2])ans+=(ll)c[0]*c[1]+(ll)c[0]*c[2]+(ll)c[1]*c[2];
51             else ans+=_cnt;
52         }
53     }
54     printf("%lld",ans);
55     return 0;
56 }

 

posted @ 2018-08-22 22:21  DCDCBigBig  阅读(251)  评论(0编辑  收藏  举报