2017国家集训队作业[agc006f]Blackout

题意:

有一个\(N*N\)的网格,一开始有\(M\)个格子被涂黑,给出这\(M\)个格子,和染色操作:如果有坐标为\((x,y),(y,z)\)的格子已被染黑,那么就可以染黑坐标为\((y,z)\)的格子。问操作到不能再操作的时候,网格里有多少个黑格子?(\(1\le N,M\le 10^5\),最开始给出的\(M\)个坐标互不相同)

题解:

在场上签到签了两个小时,看到这题一脸懵逼。= =!大概想到是把形如\((x,y),(y,z)\)格子之间连一条边,然后会产生个新点之类的。现在想想,这样的空间复杂度完全不对了,做法不可能是这个。(然而我在场上想到这的时候,决定去打暴力了)

每个\(OIer\)肯定做过一题,就是在网格上求某种合法方案,使得同一行、同一列只能有一个点。二分图匹配,对吧。那里选一个点等于行号同列之间连一条边。这题也是这样的模型。

把所有初始涂黑的点的行号同列号之间连一条单向边,那么所有点组成了若干个弱联通块,如果有边\(x\rightarrow y,y\rightarrow z\),就会产生\(z\rightarrow x\)的边,这样,我们发现一次操作一定生成了一个三元环,三染色。。。。。。。。不妨设染色顺序为\(0,1,2\)。

三种情况:

\(1.\)如果三种颜色没法全部用到,那么说明当前弱联通块无法进行操作。那么它对答案的贡献就是弱联通块的边数。

\(2.\)如果三种颜色全部用到了,但是存在某两个同颜色的点之间有边,那么说明这个弱联通块出现了环,稍微画画就能得出这个弱联通块最后一定会成为一个完全图,贡献为点数的平方。

\(3.\)其它情况,贡献为:颜色为颜色为\(0\)的点数\(*\)颜色为\(1\)的点数\(+\)颜色为\(1\)的点数\(*\)颜色为\(2\)的点数\(+\)颜色为\(2\)的点数\(*\)颜色为\(0\)的点数。

一名签到和暴力选手的啰嗦题解。。。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define fo(i,l,r) for(ll i=l;i<=r;i++)
#define of(i,l,r) for(ll i=l;i>=r;i--)
#define fe(i,u) for(ll i=head[u];i;i=e[i].next)
using namespace std;
typedef long long ll;
inline ll rd()
{
static ll x,f;
x=0,f=1;
char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
}
const ll N=100010;
struct edge{
ll v,ty,next;
edge(ll v=0,ll ty=0,ll next=0):v(v),ty(ty),next(next){}
}e[N<<1];
ll n,m,col[N],cnt[3],siz;
ll tot=0,head[N];
bool flag; inline void add(ll u,ll v,ll ty){e[++tot]=edge(v,ty,head[u]);head[u]=tot;} void dfs(ll u)
{
cnt[col[u]]++;
fe(i,u){
ll v=e[i].v,ty=e[i].ty;
siz+=(ty==1);
if(~col[v])flag|=(col[v]!=(col[u]+ty)%3);
else col[v]=(col[u]+ty)%3,dfs(v);
}
} int main()
{
#ifndef ONLINE_JUDGE
freopen("inb.txt","r",stdin);
#endif
n=rd();m=rd();
fo(i,1,m){
ll x=rd(),y=rd();
add(x,y,1);add(y,x,2);
}
memset(col,-1,sizeof col);
ll ans=0;
fo(i,1,n){
if(~col[i])continue;
cnt[col[i]=0]=cnt[1]=cnt[2]=siz=flag=0;
dfs(i);
if(flag)ans+=(cnt[0]+cnt[1]+cnt[2])*(cnt[0]+cnt[1]+cnt[2]);
else if(cnt[0]&&cnt[1]&&cnt[2])ans+=cnt[0]*cnt[1]+cnt[1]*cnt[2]+cnt[2]*cnt[0];
else ans+=siz;
}
printf("%lld\n",ans);
return 0;
}

最新文章

  1. TCP的状态 (SYN, FIN, ACK, PSH, RST, URG)
  2. iOS中常用属性的关键字的使用说明
  3. 批判性思维——Asking The Right Questions
  4. [教程]怎么用百度云观看和下载&quot;磁力链接&quot;无需下载直接观看.
  5. ecshop商品-》购买记录
  6. 玩坏JVM很简单--toString的递归调用
  7. 5 分钟上手 ECharts
  8. 导出excel乱码问题
  9. Html5实践之EventSource
  10. 【FastJSON】解决FastJson中“$ref 循环引用”的问题
  11. 设计模式14---设计模式之命令模式(Command)(行为型)
  12. Google论文之三----MapReduce
  13. Python os模块--路径、文件、系统命令等操作
  14. React 实践项目 (五)
  15. linux 文件名称前后缀操作函数----取目录函数dir、取文件名称函数notdir、取后缀函数suffix、取前缀basename、加后缀函数addsuffix、加前缀addprefix、连接函数join
  16. c# ef 排序字段动态,构建动态Lambda和扩展方法OrderBy
  17. P3373 线段树模板
  18. CSS弹性盒布局(display:flex)
  19. PHP导出Excel表
  20. 设计模式之命令模式(Command Pattern)

热门文章

  1. SQL--CLR概述
  2. UI Framework-1: Aura Views
  3. Linux 图形文件压缩/解压缩实用程序,归档管理器。
  4. 一次Linux LVM VG丢失完整找回过程记录
  5. numpy基础篇-简单入门教程1
  6. 【Henu ACM Round#17 F】Upgrading Array
  7. 【Educational Codeforces Round 37 E】Connected Components?
  8. 18.angularJS服务
  9. FTP配置说明
  10. 为什么选择Sqoop1