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;
} 
京公网安备 11010502036488号