现在给出“控制”的定义:对一个点u,设点v在其子树上,且 dis(u,v)≤av ,则称u控制v。
要求求出每个点控制了多少个点
模拟dfs过程,我们很容易发现dfs到点u时,其祖先节点到根的dis值都已经算出,且是单调递增,所以我们可以用二分或者倍增,在log的时间复杂度内找到深度最小的满足 dis(u,v)≤au 的点了。找到点v后,v到fa(u)上的每个点的答案都要增加1,显然用树上差分来实现,对ans[fa[v]]–,ans[fa[u]]++
一般写法。。。用id模拟每条路的节点编号,也用于二分
复制代码
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
74
75#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; const int maxn = 2e5 + 5; typedef long long ll; ll ans[maxn], path[maxn], a[maxn], pre[maxn], cnt[maxn]; struct node { int to, len; node(){} node(int tt, int ll) : to(tt), len(ll){} }; vector<node> p[maxn]; void dfs(int x, int id, int f, ll s) { pre[id] = s; path[id] = x; // cout << 1 << endl; if(id > 1) { int l = 1, r = id, temp; while(l <= r) { int mid = (l+r)/2; if(a[x] >= s - pre[mid]) temp = mid, r = mid - 1; else l = mid + 1; } cnt[path[temp-1]]--; cnt[path[id-1]]++; } for(int i = 0; i < p[x].size(); i++) { int to = p[x][i].to; int len = p[x][i].len; dfs(to, id+1, x,len+s); } } void dfs_ans(int x) { // cout << 1 << endl; ans[x] = cnt[x]; for(int i = 0; i < p[x].size(); i++) { int to = p[x][i].to; dfs_ans(to); ans[x] += ans[to]; } } int main() { int n; while(~scanf("%d", &n)) { for(int i = 1; i <= n; i++) scanf("%lld", &a[i]); int x, y; for(int i = 1; i < n; i++) { scanf("%d%d", &x, &y); p[x].push_back(node(i+1, y)); } dfs(1, 1, 1, 0); dfs_ans(1); for(int i = 1; i <= n; i++) { printf("%lld%c", ans[i], i == n ? 'n' : ' '); } } return 0; }
orz网上大神写法,low_bountd劲啊
用队列模拟一条路上的节点
复制代码
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#include<bits/stdc++.h> //#define make_pair MP using namespace std; typedef __int64 ll; typedef pair<ll, int> PII; const int MAXN = 2e5+5; vector<PII> G[MAXN], path; ll dep[MAXN]; int sum[MAXN], a[MAXN]; void dfs(int u) { path.push_back(make_pair(dep[u], u)); int it = lower_bound(path.begin(), path.end(), make_pair(dep[u]-a[u],-1))-path.begin()-1; //对vec用二分函数 if(it >= 0) sum[path[it].second]--; for(int i = 0; i < G[u].size(); i++) { int v = G[u][i].first, w = G[u][i].second; dep[v] = dep[u]+w; dfs(v); sum[u] += sum[v]+1; } path.pop_back(); } int main() { memset(sum, 0, sizeof(sum)); int n; cin >> n; for(int i = 1; i <= n; i++) scanf("%d", &a[i]); for(int i = 2; i <= n; i++) { int t, w; scanf("%d%d", &t, &w); G[t].push_back(make_pair(i, w)); } dep[1] = 0; dfs(1); for(int i = 1; i <= n; i++) printf("%d ", sum[i]); return 0; }
最后
以上就是动人香氛最近收集整理的关于Codeforces 739B Alyona and a tree (树上差分+二分)的全部内容,更多相关Codeforces内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复