CodeForces 739B Alyona and a tree (二分+树上差分)

<题目链接>

题目大意:

给定一颗带权树,树的根是1,树上每个点都有点权,并且还有边权。现在给出“控制”的定义:对一个点u,设v为其子树上的节点,且$dis(u,v)≤val[v]$,则称u控制v。求出每个点控制的点数。

解题分析:

处理出所有点到根的距离$dist$,然后任意两点之间的距离为$dist[v]-dist[u]$($v$为$u$的子树中的节点)。因为在每条链上,$dist$由根向子树深搜的过程中都是递增的,所以可以用二分快速找到能够控制当前节点的$dep$最浅的父亲节点,然后利用树上差分进行高效的个数统计。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>
inline void read(T&x){        
    x=0;int f=1;char ch=getchar();
    while(ch<'0' ||ch>'9'){ if(ch=='-')f=-1; ch=getchar(); }
    while(ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
    x*=f;
}
#define REP(i,s,t) for(int i=s;i<=t;i++)
#define fi first
#define se second
#define pb push_back
typedef long long ll;
const int N = 2e5+5;
int n,m,cnt,loc[N];
ll val[N],dist[N],sum[N],dfn[N];
typedef pair<int,ll>P;
vector<P>G[N];
//sum[i]表示每个点能够管辖的节点数
void dfs(int u){
    dfn[++cnt]=dist[u];loc[cnt]=u;
    int cur=lower_bound(dfn+1,dfn+1+cnt,dist[u]-val[u])-dfn;//dist[v]-dist[u]<=val[v]   ===>dist[v]-val[v]<=dist[u]       //找到能够管辖这个点的深度最浅的祖先节点
    sum[loc[cur-1]]--;
    for(auto &e:G[u]){
        int v=e.fi;ll cost=e.se;
        dist[v]=dist[u]+cost;
        dfs(v);
        sum[u]+=sum[v]+1;
    }
    --cnt;    //将这个链分支中的点全部删除
}
int main(){
    read(n);
    REP(i,1,n)read(val[i]);
    REP(i,2,n){
        int u,w;read(u);read(w);
        G[u].pb(P(i,(ll)w));
    }
    dfs(1);
    REP(i,1,n)printf("%lld ",sum[i]);
}

 

posted @ 2019-05-26 12:38  悠悠呦~  阅读(260)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end