P3066 [USACO12DEC] Running Away From the Barn G(树上倍增+差分)

P3066 [USACO12DEC]Running Away From the Barn G

原题:https://www.luogu.com.cn/problem/P3066

思路:对每个节点i,倍增找到能贡献的最远的点k,问题就相当于i点到k点路径上都+1,树上差分就行。如差分数组cf[i]++,cf[fa[k]]--。

 

#include<iostream>
#include<algorithm>
#include<fstream>
#include<cstring>
#include<cstdio>
#include<sstream>
#include<vector>
#include<stack>
#include<deque>
#include<cmath>
#include<map>
#include<queue>
#include<bitset>
//#include<hash_map>
#define sd(x) scanf("%d",&x)
#define lsd(x) scanf("%lld",&x)
#define ms(x,y) memset(x,y,sizeof x)
#define fu(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define all(a) a.begin(),a.end()
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
//using namespace __gnu_cxx;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int maxn=2e5+79;
//const int mod=1e9+7;
const int INF=1e9+7;
const double pi=acos(-1);
struct od
{
    int to,nxt;
    ll val;
}e[maxn<<1];
ll n,m,Ev,p;
ll dis[maxn];
ll f[maxn][32],d[maxn],head[maxn],cf[maxn];
void addEdge(int u,int v,ll c)
{
    e[++Ev].to=v;
    e[Ev].nxt=head[u];
    e[Ev].val=c;
    head[u]=Ev;
}
void dfs1(int u,int prev,int dep)
{
    //这次dfs是预处理倍增和dis[i],点i到根的距离
    f[u][0]=prev;d[u]=dep;
    fu(i,1,30) f[u][i]=f[f[u][i-1]][i-1];
    for(int i=head[u];i!=-1;i=e[i].nxt)
    {
        int v=e[i].to;
        if(v==prev) continue;
        dis[v]=dis[u]+e[i].val;
        dfs1(v,u,dep+1);
    }
}
bool jud(int u,int ff)
{
    return dis[u]-dis[ff]<=m;
}
ll find(int u,int fir)
{
    //不断倍增找距离<=t的父节点
    int k=u;
    fu(i,0,30)
    {
        int ff=f[u][i];
        if(ff&&jud(fir,ff)) k=ff;
        else break;
    }
    return k;
}
void work(int u)
{
    int k=u;
    while(k!=find(k,u)) k=find(k,u);
    cf[u]++,cf[f[k][0]]--;
}
void dfs2(int u,int prev)
{
    //这次dfs是进行差分
    work(u);//差分标记
    for(int i=head[u];i!=-1;i=e[i].nxt)
    {
        int v=e[i].to;
        if(v==prev) continue;
        dfs2(v,u);
    }
}
void dfs0(int u,int fa)
{
    //这次dfs是求差分后结果
    for(int i=head[u];i!=-1;i=e[i].nxt)
    {
        int v=e[i].to;
        if(v==fa) continue;
        dfs0(v,u);
        cf[u]+=cf[v];
    }
}
int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    ms(head,-1);
    cin>>n>>m;
    fu(i,2,n)
    {
        ll u,v;cin>>u>>v;
        addEdge(i,u,v);addEdge(u,i,v);
    }
    dfs1(1,0,1);
    dfs2(1,0);
    dfs0(1,0);
    fu(i,1,n) cout<<cf[i]<<endl;
    return 0;
}

 

posted on 2020-10-03 17:45  Aminers  阅读(128)  评论(0编辑  收藏  举报

导航