题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1453

题意:一个 n*n 的矩阵,每个位置有黑/白两种颜色,有 m 次操作,每次可以翻转其中一个位置的格子颜色,问每次操作后黑色和白色连通块的个数。

题解:考虑若没有翻转颜色的操作时,可以用并查集来找出两种连通块的个数,加上修改的操作,可以用线段树维护并查集的信息。对每列建线段树,合并时将边界合并,修改从叶子到根进行合并,详见代码~

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define ll long long
  4. #define ull unsigned long long
  5. #define mst(a,b) memset((a),(b),sizeof(a))
  6. #define mp(a,b) make_pair(a,b)
  7. #define pi acos(-1)
  8. #define pii pair<int,int>
  9. #define pb push_back
  10. const int INF = 0x3f3f3f3f;
  11. const double eps = 1e-;
  12. const int MAXN = 3e5 + ;
  13. const int MAXM = 1e7 + ;
  14. const ll mod = 1e9 + ;
  15.  
  16. int n, m;
  17. int s[][], fa[ * ];
  18.  
  19. int id(int x,int y) {
  20. return x * n + y;
  21. }
  22.  
  23. int findd(int x) {
  24. return x == fa[x] ? x : fa[x] = findd(fa[x]);
  25. }
  26.  
  27. struct node {
  28. int l[],r[],ans[];
  29. }st[<<];
  30.  
  31. node mergee(node &a,node &b,int mid) {
  32. node c;
  33. for(int i = ; i <= n; i++) {
  34. c.l[i] = a.l[i], c.r[i] = b.r[i];
  35. fa[a.l[i]] = a.l[i], fa[a.r[i]] = a.r[i];
  36. fa[b.l[i]] = b.l[i], fa[b.r[i]] = b.r[i];
  37. }
  38. for(int i = ; i < ; i++) c.ans[i] = a.ans[i] + b.ans[i];
  39. for(int i = ; i <= n; i++) {
  40. if(s[i][mid] == s[i][mid + ]) {
  41. int x = findd(a.r[i]), y = findd(b.l[i]);
  42. if(x == y) continue;
  43. c.ans[s[i][mid]]--, fa[x] = y;
  44. }
  45. }
  46. for(int i = ; i <= n; i++) {
  47. c.l[i] = findd(c.l[i]);
  48. c.r[i] = findd(c.r[i]);
  49. }
  50. return c;
  51. }
  52.  
  53. void build(int rt,int l,int r) {
  54. if(l == r) {
  55. st[rt].ans[] = st[rt].ans[] = ;
  56. for(int i = ; i <= n; i++) {
  57. st[rt].l[i] = st[rt].r[i] = fa[id(i,l)] = id(i,l);
  58. st[rt].ans[s[i][l]]++;
  59. }
  60. for(int i = ; i <= n; i++) {
  61. if(s[i][l] == s[i - ][l]) {
  62. st[rt].l[i] = st[rt].r[i] = fa[id(i,l)] = fa[id(i - ,l)];
  63. st[rt].ans[s[i][l]]--;
  64. }
  65. }
  66. return ;
  67. }
  68. int mid = (l + r) >> ;
  69. build(rt<<,l,mid);
  70. build(rt<<|,mid + ,r);
  71. st[rt] = mergee(st[rt<<],st[rt<<|],mid);
  72. }
  73.  
  74. void update(int rt,int l,int r,int pos) {
  75. if(l == r) {
  76. st[rt].ans[] = st[rt].ans[] = ;
  77. for(int i = ; i <= n; i++) {
  78. st[rt].l[i] = st[rt].r[i] = fa[id(i,l)] = id(i,l);
  79. st[rt].ans[s[i][l]]++;
  80. }
  81. for(int i = ; i <= n; i++) {
  82. if(s[i][l] == s[i - ][l]) {
  83. st[rt].l[i] = st[rt].r[i] = fa[id(i,l)] = fa[id(i - ,l)];
  84. st[rt].ans[s[i][l]]--;
  85. }
  86. }
  87. return ;
  88. }
  89. int mid = (l + r) >> ;
  90. if(pos <= mid) update(rt<<,l,mid,pos);
  91. else update(rt<<|,mid + ,r,pos);
  92. st[rt] = mergee(st[rt<<],st[rt<<|],mid);
  93. }
  94.  
  95. int main() {
  96. #ifdef local
  97. freopen("data.txt", "r", stdin);
  98. // freopen("data.txt", "w", stdout);
  99. #endif
  100. scanf("%d",&n);
  101. for(int i = ; i <= n; i++)
  102. for(int j = ; j <= n; j++)
  103. scanf("%d",&s[i][j]);
  104. build(,,n);
  105. scanf("%d",&m);
  106. while(m--) {
  107. int x,y;
  108. scanf("%d%d",&x,&y);
  109. s[x][y] ^= ;
  110. update(,,n,y);
  111. printf("%d %d\n",st[].ans[],st[].ans[]);
  112. }
  113. return ;
  114. }

BZOJ 1453 (线段树+并查集)的更多相关文章

  1. BZOJ 3211 线段树+并查集

    思路: 我们很容易发现 一个数开根号 开几(很小)次 就到了1 1 再怎么开 都是1 由于这个性质 我们就可以用并查集 了 //By SiriusRen #include <cmath> ...

  2. [WC2005]双面棋盘(线段树+并查集)

    线段树+并查集维护连通性. 好像 \(700ms\) 的时限把我的常数超级大的做法卡掉了, 必须要开 \(O_2\) 才行. 对于线段树的每一个结点都开左边的并查集,右边的并查集,然后合并. \(Co ...

  3. 2022.02.27 CF811E Vladik and Entertaining Flags(线段树+并查集)

    2022.02.27 CF811E Vladik and Entertaining Flags(线段树+并查集) https://www.luogu.com.cn/problem/CF811E Ste ...

  4. [BZOJ 3123] [SDOI 2013]森林(可持久化线段树+并查集+启发式合并)

    [BZOJ 3123] [SDOI 2013]森林(可持久化线段树+启发式合并) 题面 给出一个n个节点m条边的森林,每个节点都有一个权值.有两种操作: Q x y k查询点x到点y路径上所有的权值中 ...

  5. bzoj 2054: 疯狂的馒头(线段树||并查集)

    链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2054 线段树写法: 点的颜色只取决于最后一次染的颜色,所以我们可以倒着维护,如果当前区间之前 ...

  6. 【BZOJ 4662】 4662: Snow (线段树+并查集)

    4662: Snow Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 136  Solved: 47 Description 2333年的某一天,临冬突 ...

  7. BZOJ 3319 黑白树 并查集+线段树

    这这这这这这什么毒瘤题!!!!!!!!!!!!!!!!!!!!!!!!!!!! 卡LCT(优秀的LCT由于是均摊本身就带着2,3的常数在,而且这道题对于LCT标记十分难维护,又得乘上4,5然后就炸了) ...

  8. BZOJ 2733 [HNOI2012]永无乡 ——线段树 并查集

    用并查集维护联通块. 用线段树的合并来合并联通块. 自己YY了一个写法. #include <map> #include <cmath> #include <queue& ...

  9. poj 2528 Mayor's posters 线段树 || 并查集 离线处理

    题目链接 题意 用不同颜色的线段覆盖数轴,问最终数轴上有多少种颜色? 注:只有最上面的线段能够被看到:即,如果有一条线段被其他的线段给完全覆盖住,则这个颜色是看不到的. 法一:线段树 按题意按顺序模拟 ...

随机推荐

  1. [LuoguP2159][SHOI2009]舞会_动态规划_高精度_排列组合

    舞会 题目链接:https://www.luogu.org/problem/P2159 数据范围:略. 题解: 不会.... 看了题解觉得自己好傻逼啊

  2. 原生js实现图片的3d效果

    <!doctype html><html lang="en"><head><meta charset="UTF-8"& ...

  3. No package 'eventlog' found

    syslog-ng のインスト�ル手� ●ダウンロ�ドサイト http://www.balabit.com/downloads/files/syslog-ng/sources/stable/src/ ...

  4. Git初始化配置以及配置github

    1,配置用户名和邮箱(这里是我github中配置的用户名和邮箱),执行下面命令后,在C:\Users\yaosq盘下会出现一个全局文件.gitconfig. git config --global u ...

  5. 【AtCoder】ARC070

    ARC070 C - Go Home 题目大意:一只袋鼠第i秒可以向左或向右跳i步或者不跳,问从0跳到x的最小时间 就是1,2,3,4...k总和超过x的最小的k,因为如果超过了x的那部分需要减掉的那 ...

  6. 网站页面顶部出现空白行&#65279字符的原因以及完美解决办法

    转自个人博客:https://www.hurbai.com 有时候网页头部会出现一个空白行,查看源码发现body开头初有一个非法字符 // 如果是Windows系统,修改为:$WIN = 1; $W ...

  7. Synchronized&Lock&AQS详解

    加锁目的:由于线程执行的过程是不可控的,所以需要采用同步机制来协同对对象可变状态的访问. 加锁方式:java锁分为两种--显示锁和隐示锁,本质区别在于显示锁需要的是程序员自己手动的进行加锁与解锁如Re ...

  8. kubernetes 实现redis-statefulset集群

    Kubernetes 通过statefulset部署redis cluster集群 部署redis集群方式的选择 Statefulset Service&depolyment 对于redis, ...

  9. SparkSQL读取HBase数据

    这里的SparkSQL是指整合了Hive的spark-sql cli(关于SparkSQL和Hive的整合,见文章后面的参考阅读). 本质上就是通过Hive访问HBase表,具体就是通过hive-hb ...

  10. 使用python+selenium获得b站今日播放的动漫

    from selenium import webdriver browser=webdriver.Chrome() browser.get('https://www.bilibili.com/anim ...