Codeforces2020D Connect the Dots(观察 + 并查集 + 差分)
题意
多组数据。数轴上有
个点,编号为 ,对这些点做 次操作。
每次操作给出三个整数。将点 两两相连。问做完所有的操作之后,有多少个连通块。
数据范围:
题解
对于连通块相关的问题,通常考虑用并查集
合并。但是如果暴力合并的话,时间复杂度为
仔细观察发现,上界
很小,只有
对于合并操作,我们只需要标记一下,哪些点需要和前面(或后面)的邻点合并,最后再统一处理。
对于标记,我们可以差分
处理。
时间复杂度为
点击查看代码
#include <cstdio>
#include <iostream>
using i64 = long long;
inline int read() {
int res = 0; bool sym = false; char ch = getchar();
while (ch < '0' || ch > '9') sym |= ch == '-', ch = getchar();
while (ch >= '0' && ch <= '9') res = (res << 3) + (res << 1) + (ch & 15), ch = getchar();
return sym ? -res : res;
}
constexpr int N = 2e5 + 50, M = 10;
int T, n, m, a, d, k, tag[M + 1][N], par[N], ans;
int find(int x) {
return par[x] == x ? x : par[x] = find(par[x]);
}
void merge(int x, int y) {
x = find(x); y = find(y); if (x != y) par[y] = x;
}
void solve() {
n = read(); m = read(); ans = 0;
for (int i = 1; i <= n; i++) {
par[i] = i;
}
for (int d = 1; d <= M; d++) {
for (int i = 1; i <= n; i++) {
tag[d][i] = 0;
}
}
for (int i = 1; i <= m; i++) {
a = read(); d = read(); k = read();
if (k) {
// 差分
tag[d][a + d]++;
tag[d][a + (k + 1) * d]--;
}
}
for (int d = 1; d <= M; d++) {
for (int i = 1; i <= n; i++) {
if (i - d >= 1) {
tag[d][i] += tag[d][i - d];
}
}
}
for (int d = 1; d <= M; d++) {
for (int i = 1; i <= n; i++) {
if (tag[d][i]) {
merge(i, i - d);
}
}
}
for (int i = 1; i <= n; i++) {
if (find(i) == i) {
ans++;
}
}
printf("%d\n", ans);
}
int main() {
for (T = read(); T; T--) {
solve();
}
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步