2019 Nowcoder Multi-University Training Contest 4 E Explorer
线段树分治。
把size看成时间,相当于时间 $l$ 加入这条边,时间 $r+1$ 删除这条边。
注意把左右端点的关系。
#include <bits/stdc++.h> const int N = 2e5 + 7; int X[N], Y[N], top; struct DSU { int fa[N], sz[N]; int find(int x) { while (x != fa[x]) x = fa[x]; return x; } void merge(int x, int y) { x = find(x), y = find(y); if (x == y) return; if (sz[x] > sz[y]) std::swap(x, y); sz[y] += sz[x]; fa[x] = y; X[++top] = x; Y[top] = y; } void undo(int last) { for (; top > last; top--) { sz[Y[top]] -= sz[X[top]]; fa[X[top]] = X[top]; } } void clear(int n) { for (int i = 0; i <= n; i++) fa[i] = i, sz[i] = 1; } } dsu; int a[N], cnt, n, m, ans; struct Node { int u, v, x, y; }; void solve(int l, int r, const std::vector<Node> &vec) { if (vec.empty()) return; int temp = top, mid = l + r >> 1; std::vector<Node> L, R; for (auto p: vec) { if (p.x <= l && p.y >= r) { dsu.merge(p.u, p.v); } else { if (p.x <= mid) L.push_back(p); if (p.y > mid) R.push_back(p); } } if (dsu.find(1) == dsu.find(n)) { /*if (l == 4) { for (int i = 1; i <= top; i++) printf("%d %d\n", X[i], Y[i]); }*/ ans += a[r] - a[l - 1]; dsu.undo(temp); return; } if (l == r) { dsu.undo(temp); return; } solve(l, mid, L); solve(mid + 1, r, R); dsu.undo(temp); } int main() { freopen("in.txt", "r", stdin); std::vector<Node> vec; scanf("%d%d", &n, &m); vec.resize(m); for (int i = 0; i < m; i++) { scanf("%d%d%d%d", &vec[i].u, &vec[i].v, &vec[i].x, &vec[i].y); a[cnt++] = vec[i].x - 1, a[cnt++] = vec[i].y; } a[cnt++] = 0; std::sort(a, a + cnt); cnt = std::unique(a, a + cnt) - a; for (int i = 0; i < m; i++) { vec[i].x = std::lower_bound(a, a + cnt, vec[i].x) - a; vec[i].y = std::lower_bound(a, a + cnt, vec[i].y) - a; } dsu.clear(n); solve(1, cnt - 1, vec); printf("%d\n", ans); return 0; }

浙公网安备 33010602011771号