P1600 天天爱跑步

· · 题解

P1600 天天爱跑步 [题解]

题目简述

在一棵树上,有 m 个玩家同时出发,第 i 个玩家的起点为 s_i,终点为 t_i ,每秒走一条边 。每个节点上有一个观察员,一个玩家在第 w_j 秒正好到达了结点 j 会被观察到,问每个观察员会观察到多少人。

6 3 //n m
2 3 
1 2 
1 4 
4 5 
4 6 
0 2 5 1 2 3 //w[i]
1 5 
1 3 
2 6 
2 0 0 1 1 1

分析

代码实现

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=300000,LG=20;
int n,m,tot=0,head[N],w[N],fa[N][LG+1],d[N];
int bu1[N],bu2[N*2+1000],cnt_st[N],ans[N],dis[N],s[N],t[N];
int tot1=0,tot2=0,head1[N],head2[N];
struct node
{
    int next,to;
}e[N*2],e1[N*2],e2[N*2];
void add(int x,int y)
{
    e[++tot].next=head[x];
    e[tot].to=y;
    head[x]=tot;
}
void add1(int x,int y)
{
    e1[++tot1].next=head1[x];
    e1[tot1].to=y;
    head1[x]=tot1;
}
void add2(int x,int y)
{
    e2[++tot2].next=head2[x];
    e2[tot2].to=y;
    head2[x]=tot2;
}
void dfs(int x,int f,int dep)
{
    fa[x][0]=f,d[x]=dep;
    for(int i=1;(1<<i)<=d[x];i++)fa[x][i]=fa[fa[x][i-1]][i-1];
    for(int i=head[x];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v!=f)dfs(v,x,dep+1);
    }
}
int lca(int x,int y)
{
    if(d[x]<d[y])swap(x,y);
    for(int i=LG;i>=0;i--)
        if(d[x]-(1<<i)>=d[y])   x=fa[x][i];
    if(x==y)return x;
    for(int i=LG;i>=0;i--)
    {
        if(fa[x][i]!=fa[y][i])
            x=fa[x][i],y=fa[y][i];
    }
    return fa[x][0];
}
void dfs2(int x,int f)
{
    int bu1_save=bu1[d[x]+w[x]],bu2_save=bu2[w[x]-d[x]+N];
    for(int i=head[x];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v!=f)
        {
            dfs2(v,x);
        }
    }   
    bu1[d[x]]+=cnt_st[x];
    for(int i=head1[x];i;i=e1[i].next)
    {
        int v=e1[i].to;
        bu2[dis[v]-d[x]+N]++;
    }
    ans[x]+=bu1[d[x]+w[x]]-bu1_save+bu2[w[x]-d[x]+N]-bu2_save;
    for(int i=head2[x];i;i=e2[i].next)
    {
        int v=e2[i].to;
        bu1[d[s[v]]]--;
        bu2[dis[v]-d[t[v]]+N]--;
    }
}
signed main()
{
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n-1;i++)
    {
        int x,y;
        scanf("%lld%lld",&x,&y);
        add(x,y),add(y,x);
    }
    dfs(1,1,0);
    for(int i=1;i<=n;i++)cin>>w[i];
    for(int i=1;i<=m;i++)
    {
        scanf("%lld%lld",&s[i],&t[i]);
        int o=lca(s[i],t[i]);
        add1(t[i],i);
        add2(o,i);
        cnt_st[s[i]]++;
        dis[i]=d[s[i]]+d[t[i]]-2*d[o];
        if(d[o]+w[o]==d[s[i]])ans[o]--;
    }
    dfs2(1,1);
    for(int i=1;i<=n;i++)printf("%lld ",ans[i]);
    return 0;
}

其他

洛谷原题:https://www.luogu.com.cn/problem/P1600 。

博客:https://www.cnblogs.com/tommyjin/articles/18415033 。

洛谷专栏:https://www.luogu.com.cn/article/h2nvb8ow 。

演示图片(.PNG):https://cdn.luogu.com.cn/upload/image_hosting/2pkuqdnl.png 。

演示图片(.SVG):http://218.201.91.220:8989/s/K3x2EZT...。