F. Number of Components

并查集,每次修改考虑的是这个修改带来的贡献,就是和相邻颜色的对比,如果不考虑先不考虑颜色覆盖,那么添加颜色首先会产生一个新的连通块,然后考虑合并,每合并一次就会减少一个连通块。

题目转化成了对每一种颜色考虑,然后看这个颜色的改变。

对于每种颜色,会有两种:添加一个颜色(正序处理),颜色被覆盖(逆序处理)

而对于颜色被覆盖,只需要逆序考虑即可。每次只考虑贡献,因此最终要求个前缀和。

#include<bits/stdc++.h>using namespace std;constexpr int N=310,M=2000010;
int fa[2*M];
int n,m,k;
int id[N][N],idx;
int a[N][N],cur;
int ans[M];
struct node
{int x,y;int fr,to;
}q[M];
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
void merge(int x,int y)
{x=find(x),y=find(y);if(x==y) return;fa[x]=y; cur--;
}
void solve(int x,int y)// 由于边界都设为-1 不用考虑出界问题
{if(a[x][y]==a[x-1][y]) merge(id[x][y],id[x-1][y]);if(a[x][y]==a[x+1][y]) merge(id[x][y],id[x+1][y]);if(a[x][y]==a[x][y-1]) merge(id[x][y],id[x][y-1]);if(a[x][y]==a[x][y+1]) merge(id[x][y],id[x][y+1]);
}
int main()
{ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);cin>>n>>m>>k;// 询问for(int i=1;i<=k;i++){int x,y,c;cin>>x>>y>>c;q[i]={x,y,a[x][y],c};a[x][y]=c;}memset(a,0xff,sizeof a);//边界设为-1for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a[i][j]=0;//最开始为被询问的编号都默认为0 父亲也是0for(int i=1;i<=k;i++)if(q[i].fr!=q[i].to)// 如果改变颜色{cur=1;// 新产生的连通块a[q[i].x][q[i].y]=q[i].to;id[q[i].x][q[i].y]=++idx;fa[idx]=idx;solve(q[i].x,q[i].y);// 合并一次 cur--ans[i]+=cur;}// 正着做完后a已经是最终的状态idx=0;for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) {id[i][j]=++idx;fa[idx]=idx;}for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) solve(i,j);// 逆着在做一次for(int i=k;i>=1;i--)if(q[i].fr!=q[i].to){cur=1;a[q[i].x][q[i].y]=q[i].fr;id[q[i].x][q[i].y]=++idx;fa[idx]=idx;solve(q[i].x,q[i].y);ans[i]-=cur;}ans[0]=1;//最开始的图连通块个数为1for(int i=1;i<=k;i++) ans[i]+=ans[i-1];for(int i=1;i<=k;i++) cout<<ans[i]<<'\n';return 0;
}

codeforces1303 F. Number of Components(并查集+添_正序、删_逆序)相关推荐

  1. CF1303F - Number of Components(并查集)

    CF1303F - Number of Components Solution 思路还是有点妙的. 容易想到并查集,但是并查集不容易维护删边,怎么办呢? 我们考虑拆贡献,把加边的贡献和删边的贡献拆开, ...

  2. 2019年湘潭大学程序设计竞赛(重现赛)F.Truthman or Fakeman(并查集)

    链接:https://ac.nowcoder.com/acm/problem/25579 来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他语言65536 ...

  3. 1386:打击犯罪(并查集)

    [题目描述] 某个地区有n(n≤1000)个犯罪团伙,当地警方按照他们的危险程度由高到低给他们编号为1-n,他们有些团伙之间有直接联系,但是任意两个团伙都可以通过直接或间接的方式联系,这样这里就形成了 ...

  4. [NOI2002] 银河英雄传说(带权并查集好题)

    题解: 用两个变量来维护: 1.sz[i]维护第i列元素的个数 2.pre[x]维护第x元素到当前队首的距离. 在并查集是不断维护这两个值. 至于如何维护看下图和文字解释 当然,这样维护还是不够的,对 ...

  5. 并查集(边带权,拓展域)

    整理的算法模板合集: ACM模板 目录 朴素并查集 维护size的并查集 维护到祖宗节点距离的并查集 路径压缩和按秩合并 2.5 边带权 带权并查集求二分图最小环 2.6 扩展域 2.7 集合中单个元 ...

  6. POJ1733,jzoj1779-Parity game(奇偶游戏)【带权并查集,离散化】

    正题 POJ题目链接:http://poj.org/problem?id=1733 jzoj题目链接:https://jzoj.net/senior/#main/show/1779 题目大意 长度为l ...

  7. P1955-[NOI2015]程序自动分析【并查集,离散化】

    正题 评测记录:https://www.luogu.org/recordnew/lists?uid=52918&pid=P1955 题目大意 给出若干个关系,xi≠xj   or   xi=x ...

  8. c++入门必学算法 并查集

    一.什么是并查集 并查集其实就是实现一个类似朋友圈的功能,朋友的朋友是朋友,朋友的朋友的朋友也是朋友,即只要有关系一些人就合并成为一个朋友圈. 并查集可以实现查询两个人是否是朋友,查询朋友圈的个数 二 ...

  9. ccpc长春-K. Ragdoll(启发式合并、并查集、gcd转化)map的神奇tle

    K. Ragdoll 菜死我得了 题意:给定一组点以及他们的权重(1⩽n⩽1051\leqslant n\leqslant10^51⩽n⩽105),起初所有点都是独立的点.给定三种操作: 1xv1\ ...

最新文章

  1. android setAlpha 与 getBackground().setAlpha
  2. HR与HRBP的区别
  3. 二叉搜索树c/c++代码实现
  4. Java生成pdf设置两行页脚_Itextpdf 5 html生成pdf 页眉页脚
  5. 密码登录源码(jsp+java+数据库)
  6. 超键、候选键、主键、外键、联合主键、复合主键
  7. 2020-11-13(调用约定)
  8. SharePoint 编程指南(转)
  9. Maven之自定义pom类型的基础项目
  10. linux java url 异常_Java连接虚拟机(Linux)中的Oracle数据库,连接异常~新手求解!
  11. asp.net下载文件的常用方法大全
  12. php://input 如何用?
  13. BZOJ 1006: [HNOI2008]神奇的国度( MCS )
  14. 又一灵异事件 Delphi 2007 在 Win7
  15. 蒲公英wifi怎么卸载干净_如何卸载蒲公英wifi
  16. Kafka的常用命令(包括:下载安装、后台启动)
  17. c#语言程序翻译软件,C#使用百度翻译API
  18. MySQL数据库通过data文件夹恢复数据库信息
  19. GoLand 连接远程代码库
  20. A股将迎来一大波新经济公司:几家欢喜几家愁

热门文章

  1. java 枚举工厂_在Java中使用枚举工厂,最佳做法?
  2. java换水_java-交流灌水之谁是水王?
  3. python拼图游戏_乐趣无穷的Python课堂
  4. python逐行读取数据时出现错误_python如何逐行读取数据
  5. 利用结构体数组实现重排序(详解)
  6. [SpringBoot2]容器功能_底层注解配置绑定_@Configuration@Import@Conditional@ImportResource
  7. Java 源程序与编译型运行区别
  8. 高等数学下-赵立军-北京大学出版社-题解-练习12.4
  9. C++ class实现双向循环链表(完整代码)
  10. C++string容器应用举例