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]); }
作者:is_ok
出处:http://www.cnblogs.com/00isok/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。