【Codeforces811E】Vladik and Entertaining Flags [线段树][并查集]

Vladik and Entertaining Flags

Time Limit: 20 Sec  Memory Limit: 512 MB

Description

  n * m的矩形,每个格子上有一个数字代表颜色。

  q次询问,询问[l, r]有几个连通块,若颜色相同并且连通则属于同一个连通块。

Input

  输入第一行n,m,q。
  然后一个n*m的矩形。
  之后q行,每行两个整数l,r。

Output

  输出q行,对于每个询问输出答案。

Sample Input

  4 5 4
  1 1 1 1 1
  1 2 2 3 3
  1 1 1 2 5
  4 4 5 5 5
  1 5
  2 5
  1 2
  4 5

Sample Output

  6
  7
  3
  4

HINT

  1 ≤ n ≤ 10, 1 ≤ m, q ≤ 1e5, 1 ≤ l ≤ r ≤ m

Solution

  我们运用线段树,线段树一个节点i维护这个点表示的[L, R]

  具体维护Li列~Ri列连通块个数Li列连通信息Ri列连通信息Li列编号Ri列编号

  连通信息指的是n个点的连通关系,用一个[10]存下来即可。

  我们现在考虑如何合并两个区间。

  合并的时候,我们先cnt = 两个区间cnt之和,然后考虑左区间的右端信息 以及 右区间的左端信息。

  如果有两个相同的值属于不同连通块,就把它们连通起来,修改一下信息,然后cnt--。显然用并查集处理连通即可。

Code

  1 #include<iostream>
  2 #include<string>
  3 #include<algorithm>
  4 #include<cstdio>
  5 #include<cstring>
  6 #include<cstdlib>
  7 #include<cmath>
  8 using namespace std;
  9 typedef long long s64;
 10
 11 const int ONE = 1000005;
 12 const int MOD = 1e9 + 7;
 13
 14 int get()
 15 {
 16         int res = 1, Q = 1; char c;
 17         while( (c = getchar()) < 48 || c > 57)
 18             if(c == ‘-‘) Q = -1;
 19         if(Q) res = c - 48;
 20         while( (c = getchar()) >= 48 && c <= 57)
 21             res = res * 10 + c - 48;
 22         return res * Q;
 23 }
 24
 25 int n, m, Q;
 26 int col[11][ONE];
 27 int l, r;
 28
 29 int fat[ONE], total = 0;
 30 int Find(int x)
 31 {
 32         if(fat[x] == x) return x;
 33         return fat[x] = Find(fat[x]);
 34 }
 35
 36 int Un(int x, int y)
 37 {
 38         int f1 = Find(x), f2 = Find(y);
 39         if(f1 != f2) return fat[f1] = f2, 1;
 40         return 0;
 41 }
 42
 43 struct power
 44 {
 45         int val;
 46         int l[11], lid;
 47         int r[11], rid;
 48         friend power operator +(power a, power b)
 49         {
 50             power c;
 51             c.val = a.val + b.val;
 52             c.lid = a.lid, c.rid = b.rid;
 53
 54             for(int i = 1; i <= n; i++)
 55                 fat[a.l[i]] = a.l[i], fat[a.r[i]] = a.r[i],
 56                 fat[b.l[i]] = b.l[i], fat[b.r[i]] = b.r[i];
 57
 58             for(int i = 1; i <= n; i++)
 59                 if(col[i][a.rid] == col[i][b.lid])
 60                     c.val -= Un(a.r[i], b.l[i]);
 61
 62             for(int i = 1; i <= n; i++)
 63                 c.l[i] = Find(a.l[i]), c.r[i] = Find(b.r[i]);
 64
 65             return c;
 66         }
 67 }Node[ONE];
 68
 69 void Build(int i, int l, int r)
 70 {
 71         if(l == r)
 72         {
 73             Node[i].lid = Node[i].rid = l;
 74             for(int j = 1; j <= n; j++)
 75                 if(col[j - 1][l] != col[j][l])
 76                     Node[i].l[j] = Node[i].r[j] = ++total, Node[i].val++;
 77                 else
 78                     Node[i].l[j] = Node[i].r[j] = Node[i].l[j - 1];
 79             return;
 80         }
 81         int mid = l + r >> 1;
 82         Build(i << 1, l, mid), Build(i << 1 | 1, mid + 1, r);
 83         Node[i] = Node[i << 1] + Node[i << 1 | 1];
 84 }
 85
 86 power Query(int i, int l, int r, int L, int R)
 87 {
 88         if(L <= l && r <= R) return Node[i];
 89
 90         int mid = l + r >> 1;
 91         if(!(mid + 1 <= R)) return Query(i << 1, l, mid, L, R);
 92         else if(!(L <= mid)) return Query(i << 1 | 1, mid + 1, r, L, R);
 93         else return Query(i << 1, l, mid, L, R) + Query(i << 1 | 1, mid + 1, r, L ,R);
 94 }
 95
 96 int main()
 97 {
 98         n = get();    m = get();    Q = get();
 99         for(int i = 1; i <= n; i++)
100             for(int j = 1; j <= m; j++)
101                 col[i][j] = get();
102         Build(1, 1, m);
103
104         while(Q--)
105         {
106             l = get(), r = get();
107             power res = Query(1, 1, m, l, r);
108             printf("%d\n", res.val);
109         }
110
111 }

时间: 2024-10-09 17:16:10

【Codeforces811E】Vladik and Entertaining Flags [线段树][并查集]的相关文章

UVALive 4730 Kingdom 线段树+并查集

题目链接:点击打开链接 题意见白书P248 思路: 先把读入的y值都扩大2倍变成整数 然后离散化一下 用线段树来维护y轴 区间上每个点的 城市数量和联通块数量, 然后用并查集维护每个联通块及联通块的最大最小y值,还要加并查集的秩来记录每个联通块的点数 然后就是模拟搞.. T^T绝杀失败题..似乎数组开小了一点就过了,== #include<stdio.h> #include<math.h> #include<vector> #include<string.h>

UVA 1455 - Kingdom(线段树+并查集)

UVA 1455 - Kingdom 题目链接 题意:给定一些城市坐标点,连在一起的城市称为一个州,现在用两种操作,road表示把城市a,b建一条路,line表示询问一个y轴上穿过多少个州,和这些州共包含多少个城市 思路:利用并查集维护每个州的上界和下界还有城市个数,然后每次加进一条路的时候,根据两个集合的位置可以处理出区间的州和城市数如何进行加减,然后利用线段树搞就可以了 代码: #include <cstdio> #include <cstring> #include <

(线段树+并查集) Codeforces Round #416 (Div. 2) E Vladik and Entertaining Flags

In his spare time Vladik estimates beauty of the flags. Every flag could be represented as the matrix n?×?m which consists of positive integers. Let's define the beauty of the flag as number of components in its matrix. We call component a set of cel

【BZOJ-3673&amp;3674】可持久化并查集 可持久化线段树 + 并查集

3673: 可持久化并查集 by zky Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 1878  Solved: 846[Submit][Status][Discuss] Description n个集合 m个操作操作:1 a b 合并a,b所在集合2 k 回到第k次操作之后的状态(查询算作操作)3 a b 询问a,b是否属于同一集合,是则输出1否则输出0 0<n,m<=2*10^4 Input Output Sample Input 5 6

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

4662: Snow Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 136  Solved: 47 Description 2333年的某一天,临冬突降大雪,主干道已经被雪覆盖不能使用.城 主 囧·雪 决定要对主干道进行一次清扫. 临冬城的主干道可以看为一条数轴.囧·雪 一共找来了n个清理工,第 i个清理工的工作范围为[li,ri],也就是说这个清理工会把[li,ri]这一 段主干道清理干净(当然已经被清理过的部分就被忽略了).当然有可能主 干道

UVALive 4730 线段树+并查集

点击打开链接 题意:在坐标上给n个点,r的操作是将两个点连起来,l的操作是问你y=u的这条线连接的集合块数和这些集合内的点的个数 思路:很麻烦的一道题,在网上看了题意和做法后,开始了一下午的调bug过程,做法很好懂,我开了两个线段树,一个维护点代表的直线的集合个数,另一个则是路过集合内的点的个数,然后集合的判断直接用并查集就行了,这是两个核心,然后就是自己瞎写的了,代码丑的可以而且好像除了本人别人看着可能要骂人了,有兴趣研究的可以留言我来解答,那难的部分其实就是并查集合并时该怎么将这两个要维护的

【XSY2707】snow 线段树 并查集

题目描述 有\(n\)个人和一条长度为\(t\)的线段,每个人还有一个工作范围(是一个区间).最开始整条线段都是白的.定义每个人的工作长度是这个人的工作范围中白色部分的长度(会随着线段改变而改变).每一天开始时你要选择一个人满足这个人的工作长度最小(如果有多个就选编号最小的).把这个人的工作区间染黑.请你输出每天你选了哪个人. 保证工作范围中左端点和右端点单调递增. \(n\leq 300000\) 题解 先把线段离散化成很多个小区间,那么每个小区间只会被染黑一次(染黑之后不会变白). 因此每次

【CF687D】Dividing Kingdom II 线段树+并查集

[CF687D]Dividing Kingdom II 题意:给你一张n个点m条边的无向图,边有边权$w_i$.有q个询问,每次给出l r,问你:如果只保留编号在[l,r]中的边,你需要将所有点分成两个集合,使得这个划分的代价最小,问最小代价是什么.一个划分的代价是指,对于所有两端点在同一集合中的边,这些边的边权最大值.如果没有端点在同一集合中的边,则输出-1. $n,q\le 1000,m\le \frac {n(n-1)} 2,w_i\le 10^9$ 题解:先考虑暴力的做法,我们将所有边按

[HDU3710] Battle Over Cities [树链剖分+线段树+并查集+kruskal+思维]

题面 一句话题意: 给定一张 N 个点, M 条边的无向连通图, 每条边上有边权 w . 求删去任意一个点后的最小生成树的边权之和. 思路 首先肯定要$kruskal$一下 考虑$MST$里面去掉一个点,得到一堆联通块,我们要做的就是用原图中剩下的边把这些联通块穿起来 考虑这个点$u$在$MST$上的位置,可以知道有两种边:一种是从$u$的任意一个儿子的子树连到$u$的子树外面的,一种是在$u$的两个儿子的子树之间连接的 第一种情况: 考虑边$(u,v)$,没有进入$MST$中,那么若它是某个节