[CodeForces - 739B] Alyona and a tree 【树 + 差分 + 二分】

 题意:

  • 给定一颗树,每个结点有对应点权,每条边也有对应边权。如果dis<v, u> <= val[u],则说明结点u被结点v所管辖。对于每个结点,输出它管辖的结点数目。

思路:

我们定义dis[ u ]为结点u到根结点的边权和。显而易见dis<v, u> = dis[u] - dis[v],并且dis是递增

无根树转有根树,那么对于任何一条树链,树链上结点u,我们要找到dis[u] - dis[v] <= val[u],转化一下,也就是我们需要找到结点v,并且有dis[v] >= dis[u] - val[u]。由于dis[ ]的单调递增性,我们可以二分找到第一个大于等于dis[u] - val[u]的结点v,那么<v, fa(u)>中每个结点都管辖着结点u. 也就是树链<v, fa(u)>上每个结点的答案都应该加1. 

显然我们不能这么做,复杂度爆炸啊。于是想到差分,对于每一条从根结点到叶子节点的树链,我们都看成一个线性的数组。那么上述v就是右端点,fa(u)就是左端点。于是我们只需要O(1)将 -- sum[v + 1], ++ sum[fa(v)]即可,最后回溯的时候sum[u] += sum[son(u)]得到答案啦~~~~


#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#define INF 0x3f3f3f3f3f
using namespace std;

typedef long long ll;

inline int read()
{
    int x = 0, f = 1; char c = getchar();
    while(c < '0' || c > '9') { if(c == '-') f = -f; c = getchar(); }
    while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
    return x * f;
}

const int maxN = 200005;
const int maxM = 1000006;

int n, chain[maxN];
ll val[maxN], dis[maxN];
ll que[maxN], cnt; //模拟队列,存储当前树链的结点的dis
int sum[maxN];
vector<pair<int, ll> >edge[maxN];

void dfs(int u, int fa)
{
    que[++cnt] = dis[u];
    chain[cnt] = u;
    int id = lower_bound(que + 1, que + cnt, dis[u] - val[u]) - que;
    //因为需要dis[u] - dis[v] <= val[], 也就是找到dis[v]  >= dis[u] - val[u],那么路径<v, u>上u的每个祖先都要增加1
    -- sum[chain[id - 1]]; //v相当于右端点,右端点+1执行-1操作
    ++ sum[fa]; //左端点执行+1操作
    for(auto e : edge[u] )
    {
        int v = e.first;
        dis[v] = dis[u] + e.second;
        dfs(v, u);
        sum[u] += sum[v];
    }
    -- cnt;
}

int main()
{
    n = read();
    for(int i = 1; i <= n; ++ i ) val[i] = read();
    for(int v = 2; v <= n; ++ v)
    {
        int u, w;
        u = read(); w = read();
        edge[u].push_back(make_pair(v, w));
    }
    dfs(1, 0);
    for(int i = 1; i <= n; ++ i )
        printf("%d%c", sum[i], " \n"[i == n]);
    return 0;
}
发布了242 篇原创文章 · 获赞 68 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_44049850/article/details/104595723
今日推荐