WeChat Walk
给定
个点
条边的无向图,初始点权 0。
天,每天增加一个点的点权,求每个点点权比周围的点都大的天数。
,点权始终不会超过
按照度数分类,度数大于 的为大点,其余为小点。
大点不会超过 个。
修改点权时,如果是小点,可以暴力更新周围点的情况。
如果是大点,分类讨论:
周围的大点,不会超过
个,暴力更新。
周围的小点,不能暴力更新。
维护
表示大点周围小点权值的最大值,小点更新权值时更新。
观察数据范围,发现点权只有
,可以存下大点周围权值为
的有哪些小点是冠军。每次增加点权时暴力扫描权值更新小点。
容易发现每个大点最多扫描
次。
// Author: HolyK // Created: Tue Jul 20 10:22:54 2021 #include <bits/stdc++.h> #define dbg(a...) fprintf(stderr, a) template <class T, class U> inline bool smin(T &x, const U &y) { return y < x ? x = y, 1 : 0; } template <class T, class U> inline bool smax(T &x, const U &y) { return x < y ? x = y, 1 : 0; } using LL = long long; using PII = std::pair<int, int>; constexpr int N(2e5 + 5), T(512); std::vector<int> g[N], big[N], small[N / 512][10001]; int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int n, m, q; std::cin >> n >> m >> q; while (m--) { int x, y; std::cin >> x >> y; x--, y--; g[x].push_back(y); g[y].push_back(x); } std::vector<int> id(n), b; for (int i = 0; i < n; i++) { if (g[i].size() > T) { id[i] = b.size(); b.push_back(i); for (int j : g[i]) { big[j].push_back(id[i]); } } } std::vector<int> w(n), s(n), max(b.size()), ans(n); for (int t = 1; t <= q; t++) { int x, y; std::cin >> x >> y; x--; if (g[x].size() <= T) { if (!s[x]) { int max = 0; for (int i : g[x]) { smax(max, w[i]); if (s[i] && w[x] + y >= w[i]) { ans[i] += t - s[i]; s[i] = 0; } } if (w[x] + y > max) { s[x] = t; } } for (int i : big[x]) { if (s[x]) small[i][w[x] + y].push_back(x); smax(max[i], w[x] + y); } } else { if (!s[x]) { int m = max[id[x]]; for (int v : big[x]) { int i = b[v]; smax(m, w[i]); if (s[i] && w[x] + y >= w[i]) { ans[i] += t - s[i]; s[i] = 0; } } if (w[x] + y > m) s[x] = t; for (int i = w[x] + y; i > w[x]; i--) { for (int j : small[id[x]][i]) { if (s[j] && i == w[j]) { ans[j] += t - s[j]; s[j] = 0; } } } } } w[x] += y; } for (int i = 0; i < n; i++) { if (s[i]) { ans[i] += q - s[i]; } } for (int x : ans) { std::cout << x << "\n"; } return 0; }