2020-2021 ACM-ICPC Brazil Subregional Programming Contest E Party Company

题目描述

https://codeforces.com/gym/102861/problem/E

Solution

操作等价于每次选择点 $u$ 的一个连通块,块内的所有点的权值都在 $[l,r]$ 内,将这个连通块内的所有点答案加 $1$,统计每个点被加过多少次

首先注意到一个性质:父亲节点的值大于等于儿子节点的值

那么我们可以将每个操作都暴力跳到最高处,这样权值的限制变为大于等于 $l$,且只对子树进行操作

我们发现这是个经典的做法

我们进入一个点的时候把它贡献加上,离开这个点的时候再减掉

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#define maxn 100010
#define lowbit(i) ((i) & (-i))
using namespace std;

int n, m, w[maxn];

struct Edge {
int to, next;
} e[maxn]; int c1, head[maxn];
inline void add_edge(int u, int v) {
e[c1].to = v; e[c1].next = head[u]; head[u] = c1++;
}

int f[maxn][21];
void Dfs(int u, int fa) {
for (int i = head[u]; ~i; i = e[i].next) {
int v = e[i].to; if (v == fa) continue;
f[v][0] = u; Dfs(v, u);
}
}

void init_lca() {
for (int j = 1; j <= 20; ++j)
for (int i = 1; i <= n; ++i) f[i][j] = f[f[i][j - 1]][j - 1];
}

int jump(int u, int v) {
for (int i = 20; ~i; --i)
if (f[u][i] && w[f[u][i]] <= v) u = f[u][i];
return u;
}

int Bit[maxn], N;
void add(int i, int v) { while (i <= N) Bit[i] += v, i += lowbit(i); }

int get_sum(int i) {
int s = 0;
while (i) s += Bit[i], i -= lowbit(i);
return s;
}

vector<int> A[maxn]; int ans[maxn];
void dfs(int u, int fa) {
for (auto t : A[u]) add(t, 1);
ans[u] = get_sum(w[u]);
for (int i = head[u]; ~i; i = e[i].next) {
int v = e[i].to; if (v == fa) continue;
dfs(v, u);
}
for (auto t : A[u]) add(t, -1);
}

int main() { fill(head, head + maxn, -1);
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);

cin >> n >> m;
for (int i = 1; i <= n; ++i) {
int x; cin >> w[i] >> x; N = max(N, w[i]);
if (x != i) add_edge(x, i);
} Dfs(1, 0); init_lca();
for (int i = 1; i <= m; ++i) {
int x, y, z; cin >> x >> y >> z;
A[jump(x, z)].push_back(y);
} dfs(1, 0);
for (int i = 1; i <= n; ++i) cout << ans[i] << " "; cout << "\n";
return 0;
}