noip 2016 day1 T2 天天爱跑步

题目描述

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

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

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

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

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

输入格式

第一行有两个整数nnn和mmm 。其中nnn代表树的结点数量, 同时也是观察员的数量, mmm代表玩家的数量。

接下来 n−1n- 1n1行每行两个整数uuu和 vvv,表示结点 uuu到结点 vvv有一条边。

接下来一行 nnn个整数,其中第jjj个整数为WjW_jWj , 表示结点jjj出现观察员的时间。

接下来 mmm行,每行两个整数SiS_iSi,和TiT_iTi,表示一个玩家的起点和终点。

对于所有的数据,保证1≤Si,Ti≤n,0≤Wj≤n1\leq S_i,T_i\leq n, 0\leq W_j\leq n1Si,Tin,0Wjn 。

输出格式

输出1行 nnn个整数,第jjj个整数表示结点jjj的观察员可以观察到多少人。

输入输出样例

输入 #1
6 3
2 3
1 2 
1 4 
4 5 
4 6 
0 2 5 1 2 3 
1 5 
1 3 
2 6 
输出 #1
2 0 0 1 1 1 
输入 #2
5 3 
1 2 
2 3 
2 4 
1 5 
0 1 0 3 0 
3 1 
1 4
5 5 
输出 #2
1 2 1 0 1 

说明/提示

【样例1说明】

对于111号点,Wi=0W_i=0Wi=0,故只有起点为1号点的玩家才会被观察到,所以玩家111和玩家222被观察到,共有222人被观察到。

对于222号点,没有玩家在第222秒时在此结点,共000人被观察到。

对于333号点,没有玩家在第555秒时在此结点,共000人被观察到。

对于444号点,玩家111被观察到,共111人被观察到。

对于555号点,玩家111被观察到,共111人被观察到。

对于666号点,玩家333被观察到,共111人被观察到。

【子任务】

每个测试点的数据规模及特点如下表所示。 提示: 数据范围的个位上的数字可以帮助判断是哪一种数据类型。

【提示】

如果你的程序需要用到较大的栈空问 (这通常意味着需要较深层数的递归), 请务必仔细阅读选手日录下的文本当rumung:/stact.p″, 以了解在最终评测时栈空问的限制与在当前工作环境下调整栈空问限制的方法。

在最终评测时,调用栈占用的空间大小不会有单独的限制,但在我们的工作环境中默认会有 8MB8 MB8MB 的限制。 这可能会引起函数调用层数较多时, 程序发生栈溢出崩溃。

我们可以使用一些方法修改调用栈的大小限制。 例如, 在终端中输入下列命令 ulimit -s 1048576

此命令的意义是,将调用栈的大小限制修改为 1GB1 GB1GB。

例如,在选手目录建立如下 sample.cpp 或 sample.pas

将上述源代码编译为可执行文件 sample 后,可以在终端中运行如下命令运行该程序

./sample

如果在没有使用命令“ ulimit -s 1048576”的情况下运行该程序, sample会因为栈溢出而崩溃; 如果使用了上述命令后运行该程序,该程序则不会崩溃。

特别地, 当你打开多个终端时, 它们并不会共享该命令, 你需要分别对它们运行该命令。

请注意, 调用栈占用的空间会计入总空间占用中, 和程序其他部分占用的内存共同受到内存限制。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
using namespace std;
const int maxn = 300000 + 10 ;
int n,m,w[maxn];
struct Node
{int to,next;}edge[maxn * 2],edge1[maxn *2],edge2[maxn * 2];
struct node
{int lca,u,v,dis;}point[maxn];
int head[maxn * 2],cnt;
int st[maxn];

void add(int x,int y)
{
    edge[++cnt].to=y;
    edge[cnt].next=head[x];
    head[x]=cnt;
}
int cnt1,cnt2,head1[maxn * 2],head2[maxn * 2];
void add1(int x,int y)
{
    edge1[++cnt1].to=y;
    edge1[cnt1].next=head1[x];
    head1[x]=cnt1;
}
void add2(int x,int y)
{
    edge2[++cnt2].to=y;
    edge2[cnt2].next=head2[x];
    head2[x]=cnt2;
}

int f[maxn][25],Dep[maxn];
void Build_tree(int u,int fa)
{
    Dep[u]=Dep[fa]+1;
    for(int i=0;i<=19;i++) f[u][i+1]=f[f[u][i]][i];
    for(int i=head[u];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(v==fa) continue;
        f[v][0]=u;
        Build_tree(v,u);
    }
}
int ans[maxn * 2];
int Lca(int x,int y)
{
    if(Dep[x]<Dep[y]) swap(x,y);
    for(int i=20;i>=0;i--)
    {
        if(Dep[f[x][i]]>=Dep[y]) x=f[x][i];
        if(x==y) return x;
    }
    for(int i=20;i>=0;i--)
        if(f[x][i]!=f[y][i])
            x=f[x][i],y=f[y][i];
    return f[x][0];
}
int dist(int x,int y)
{return Dep[x]+Dep[y]-2*Dep[Lca(x,y)];}
int b1[maxn * 2],b2[maxn * 2];
void dfs(int u)
{
    int t1=b1[Dep[u]+w[u]],t2=b2[w[u]-Dep[u]+maxn];
    for(int i=head[u];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(v==f[u][0]) continue;
        dfs(v);
    }
    b1[Dep[u]]+=st[u];
    for(int i=head1[u];i;i=edge1[i].next)
    {
        int v=edge1[i].to;
        b2[point[v].dis-Dep[point[v].v]+maxn]++;
    }
    ans[u]+=b1[w[u]+Dep[u]]-t1+b2[w[u]-Dep[u]+maxn]-t2;
    for(int i=head2[u];i;i=edge2[i].next)
    {
        int v=edge2[i].to;
        b1[Dep[point[v].u]]--;
        b2[point[v].dis-Dep[point[v].v]+maxn]--;
    }
}
int main()
{
    cin>>n>>m;
    for(int i=1,x,y;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y);add(y,x);
    }
    for(int i=1;i<=n;i++) scanf("%d",&w[i]);
    Build_tree(1,0);
    for(int i=1,x,y;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        point[i].u=x,point[i].v=y;
        point[i].lca=Lca(x,y);
        point[i].dis=dist(x,y);
        st[point[i].u]++;
        add1(point[i].v,i);
        add2(point[i].lca,i);
        if(Dep[point[i].lca]+w[point[i].lca]==Dep[point[i].u]) ans[point[i].lca]--;
        //如果路径起点或终点刚好为LCA且LCA处是可观察到运动员的,那么我们在上行统计过程中和下行统计过程中都会对该LCA产生贡献,这样就重复计数一次!
    }
    dfs(1);
    for(int i=1;i<=n;i++) printf("%d ",ans[i]);
    return 0;
}

 

转载于:https://www.cnblogs.com/hfang/p/11485522.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值