概述
现在给出“控制”的定义:对一个点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模拟每条路的节点编号,也用于二分
#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劲啊
用队列模拟一条路上的节点
#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 739B Alyona and a tree (树上差分+二分)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复