大意
给定一个 n×m 的方格, 每格中有一个数字, 设两个方格是 联通的 , 仅当两个方格相邻且数字相同 .
q 个询问, 每次给定 l, r, 求从第 l 列至第 r 列中联通块的个数 .
数据范围
# |
% |
n |
m |
q |
1 |
15 % |
≤2 |
≤106 |
≤1.3×106 |
2 |
75 % |
≤10 |
≤105 |
≤105 |
3 |
10 % |
=1000 |
≤100 |
≤106 |
题解
这道题要分成 3 个部分, 对应上表中的三个数据范围.
#1
n≤2,m≤106,q≤1.3×106
可以发现, n≤2, 同时 m,q 很大, 考虑用前缀和解决.
设 si 为前 i 列的联通块个数.
n=1 时:
si=si−1+[ai=ai−1]
n=2 时:
si=si−1+[a1,i=a1,i−1]+[a2,i=a2,i−1]−[a1,i=a2,i∧a1,i=a1,i−1∧a2,i=a2,i−1]
查询时, 同样解决.
n=1 时:
sr−sl−1+[al=al−1]
n=2 时:
sr−sl−1+[a1,l=a1,l−1]+[a2,l=a2,l−1]−[a1,l=a1,l−1∧a2,l=a2,l−1∧a1,l=a2,l]
#2
线段树.
设 id(i,j)=(i−1)⋅m+j
每个节点存储 l,r,cnt, 分别代表该区间左端和右端的编号 (编号相同就代表数字相同, 反之不一定) , 和联通块个数.
先考虑每一列:
li,j=li−1,j,i≥2∧ai,j=ai−1,jli,j=id(i,j),otherwise
然后考虑合并
首先 cnt←cnt(ls)+cnt(rs).
对于中间的两列, 即 ls.r
和 rs.l
, 若相同, 则用 dsu 加入同一个集合, 并 cnt←cnt−1.
然后对于左右两列, l←l(ls), r←r(rs), 并要在 dsu 中查询.
合并完将 dsu 恢复.
#3
仿照 #2 的情况, 独立处理每一列, 然后合并时, 若两侧相同且不在同一个集合内, 就合并, cnt←cnt−1.