[NOIP2016]天天爱跑步

题目描述

小c同学认为跑步非常有趣,于是决定制作一款叫做《天天爱跑步》的游戏。天天爱跑步是一个养成类游戏,需要 玩家每天按时上线,完成打卡任务。

这个游戏的地图可以看作一一棵包含 N个结点和N-1 条边的树, 每条边连接两个结点,且任意两个结点存在一条路径互相可达。树上结点编号为从1到N的连续正整数。

现在有个玩家,第个玩家的 起点为Si ,终点为Ti 。每天打卡任务开始时,所有玩家在第0秒同时从自己的起点出发, 以每秒跑一条边的速度, 不间断地沿着最短路径向着自己的终点跑去, 跑到终点后该玩家就算完成了打卡任务。 (由于地图是一棵树, 所以 每个人的路径是唯一的)

小C想知道游戏的活跃度, 所以在每个结点上都放置了一个观察员。 在结点的观察员会选 择在第Wj秒观察玩家, 一个玩家能被这个观察员观察到当且仅当该玩家在第Wj秒也正好到达了结点J 。 小C想知道 每个观察员会观察到多少人?

注意: 我们认为一个玩家到达自己的终点后该玩家就会结束游戏, 他不能等待一 段时 间后再被观察员观察到。 即对于把结点J作为终点的玩家: 若他在第Wj秒重到达终点,则在结点J的观察员不能观察 到该玩家;若他正好在第Wj秒到达终点,则在结点的观察员可以观察到这个玩家。

 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

题解开始:

一眼看出将每人的运动过程分成两部分(应该没啥异议),然后发现两个性质:

1.向树根跑的人,t+dep不变;

2.向叶子跑的人,dep-t不变;

然后用两个桶存上面两个值,dfs就行。

代码:

#include<cstdio>
#include<algorithm>
using namespace std;
#define N 300005
int n,m,hed[N],cnt;
inline int rd()
{
    int f=1,c=0;char ch = getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=(c<<3)+(c<<1)+ch-'0';ch=getchar();}
    return f*c;
}
struct EDge
{
    int to;
    int nxt;
}e[2*N];
void ae(int f,int t)
{
    e[++cnt].to=t;
    e[cnt].nxt=hed[f];
    hed[f]=cnt;
}
int tp[N],fa[N],dep[N],son[N],siz[N];
void dfs0(int u)
{
    siz[u]=1;
    for(int j=hed[u];j;j=e[j].nxt)
    {
        int to = e[j].to;
        if(to==fa[u])continue;
        fa[to]=u;
        dep[to]=dep[u]+1;
        dfs0(to);
        if(siz[to]>siz[son[u]])
        {
            son[u]=to;
        }
        siz[u]+=siz[to];
    }
}
void dfs1(int u,int tpp)
{
    tp[u]=tpp;
    if(!son[u])return ;
    dfs1(son[u],tpp);
    for(int j=hed[u];j;j=e[j].nxt)
    {
        int to = e[j].to;
        if(to==fa[u]||to==son[u])continue;
        dfs1(to,to);
    }
}
int get_lca(int a,int b)
{
    while(tp[a]!=tp[b])
    {
        if(dep[tp[a]]<dep[tp[b]])swap(a,b);
        a=fa[tp[a]];
    }
    return dep[a]>dep[b]?b:a;
}
int w[N],ans[N];
int dfsx[N][2],cnt1[2];//0 dep+w 1 dep-w
struct Node
{
    int v,delta,nxt;
}d1[N<<1][2];
void aN(int x,int tip,int v,int delta)
{
    d1[++cnt1[tip]][tip].v=v;
    d1[cnt1[tip]][tip].delta=delta;
    d1[cnt1[tip]][tip].nxt=dfsx[x][tip];
    dfsx[x][tip]=cnt1[tip];
}
int T[N<<1][2];
void dfs(int u)
{
    int tmp = T[dep[u]+w[u]+N][0]+T[dep[u]-w[u]+N][1];
    for(int j=hed[u];j;j=e[j].nxt)
    {
        int to = e[j].to;
        if(to==fa[u])continue;
        dfs(to);
    }
    for(int tp = 0;tp<=1;tp++)
    {
        for(int j=dfsx[u][tp];j;j=d1[j][tp].nxt)
        {
            T[d1[j][tp].v+N][tp]+=d1[j][tp].delta;
        }
    }
    ans[u]+=(T[dep[u]+w[u]+N][0]+T[dep[u]-w[u]+N][1])-tmp;
} 
int main()
{
    n=rd(),m=rd();
    for(int f,t,i=1;i<n;i++)
    {
        f=rd(),t=rd();
        ae(f,t);
        ae(t,f);
    }
    dfs0(1);
    dfs1(1,1);
    for(int i=1;i<=n;i++)
    {
        w[i]=rd();
    }
    for(int f,t,i=1;i<=m;i++)
    {
        f=rd(),t=rd();
        int LCA = get_lca(f,t);
        if(dep[LCA]+w[LCA]==dep[f])ans[LCA]--;
        aN(f,0,dep[f],1);
        aN(fa[LCA],0,dep[f],-1);
        aN(t,1,2*dep[LCA]-dep[f],1);
        aN(fa[LCA],1,2*dep[LCA]-dep[f],-1);
    }
    dfs(1);
    for(int i=1;i<=n;i++)
    {
        printf("%d ",ans[i]);
    }
    printf("\n");
    return 0;
}

 

posted @ 2018-09-04 00:39  LiGuanlin  阅读(156)  评论(0编辑  收藏  举报