NOIP2016天天爱跑步

Posted 人间失格

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NOIP2016天天爱跑步相关的知识,希望对你有一定的参考价值。

 

Description

小C同学认为跑步非常有趣,于是决定制作一款叫做《天天爱跑步》的游戏。《天天爱跑步》是一个养成类游戏,需要玩家每天按时上线,完成打卡任务。 
这个游戏的地图可以看作一棵包含n个结点和n-1条边的树,每条边连接两个结点,且任意两个结点存在一条路径互相可达。树上结点编号为从1到n的连续正整数。 
现在有m个玩家,第i个玩家的起点为Si,终点为Ti。每天打卡任务开始时,所有玩家在第0秒同时从自己的起点出发,以每秒跑一条边的速度,不间断地沿着最短路径向着自己的终点跑去,跑到终点后该玩家就算完成了打卡任务。(由于地图是一棵树,所以每个人的路径是唯一的)

Input

第一行有两个整数n和m。其中n代表树的结点数量,同时也是观察员的数量,m代表玩家的数量。 
接下来n-1行每行两个整数u和v,表示结点u到结点v有一条边。 
接下来一行n个整数,其中第j个整数为Wj,表示结点j出现观察员的时间。 
接下来m行,每行两个整数Si和Ti,表示一个玩家的起点和终点。 
对于所有的数据,保证1≤Si,Ti≤n,0≤ Wj ≤n。

Output

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

Sample Input

6 3 
2 3 
1 2 
1 4 
4 5 
4 6 
0 2 5 1 2 3 
1 5 
1 3 
2 6

Sample Output

2 0 0 1 1 1

Hint

提示: 
对于1号点,W1=0,故只有起点为1号点的玩家才会被观察到,所以玩家1和玩家2被观察到,共2人被观察到。 
对于2号点,没有玩家在第2秒时在此结点,共0人被观察到。 
对于3号点,没有玩家在第5秒时在此结点,共0人被观察到。 
对于4号点,玩家1被观察到,共1人被观察到。 
对于5号点,玩家2被观察到,共1人被观察到。 
对于6号点,玩家3被观察到,共1人被观察到。

Pic

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

Source

NOIP2016, LCA,搜索dfs

 

题解:

  见 ljh学长的博客吧,好久没有看到这么好的题解了,代码基本和他差不多。题解也是看他的看懂的。  http://www.cnblogs.com/ljh2000-jump/p/6189053.html

 

代码:

 

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <vector>
#define MAXN 600011
#define move 300000
using namespace std;
int dep[MAXN],f[MAXN][20];
vector<int> sy1[MAXN],sy2[MAXN],sy3[MAXN];
int ans[MAXN],tong[MAXN],num[MAXN],val[MAXN];
int w[MAXN],n,m,numm=0,maxx=0;
struct edge{
    int first,next,to;
}a[MAXN];
struct query{
    int from,to,lca,len;
}q[MAXN];

void addedge(int from,int to){
    a[++numm].to=to;a[numm].next=a[from].first;a[from].first=numm;
}

void pre(int now,int ff){
    dep[now]=dep[ff]+1;f[now][0]=ff;maxx=max(maxx,dep[now]);
    for(int i=a[now].first;i;i=a[i].next){
        int to=a[i].to;
        if(to==ff) continue;
        pre(to,now);
    }
}

int Lca(int x,int y){
    if(dep[x]<dep[y]) swap(x,y);int t=0;while((1<<t)<=dep[x]) t++;t--;
    for(int i=t;i>=0;i--)
        if(dep[x]-(1<<i)>=dep[y]) x=f[x][i];
    if(x==y) return x;
    for(int i=t;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    return f[x][0];
}

void dfs1(int x,int fa){
    int now=w[x]+dep[x],cut;if(now<=maxx) cut=tong[now];
    for(int i=a[x].first;i;i=a[i].next){
        int to=a[i].to;if(to==fa) continue;
        dfs1(to,x);
    }
    tong[dep[x]]+=val[x];if(now<=maxx) ans[x]=tong[now]-cut;
    int len=sy1[x].size();for(int i=0;i<len;i++) tong[dep[sy1[x][i]]]--;
}

void dfs2(int x,int fa){
    int now=dep[x]-w[x],cut; now+=move; cut=num[now];
    for(int i=a[x].first;i;i=a[i].next) {
        int to=a[i].to;
                if(to==fa) continue;
        dfs2(to,x);
    }
        int len=sy2[x].size();
    for(int i=0;i<len;i++) num[move+sy2[x][i]]++;
    ans[x]+=num[now]-cut;
        len=sy3[x].size();
    for(int i=0;i<len;i++) num[move+sy3[x][i]]--;
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n-1;i++){
        int x,y;scanf("%d%d",&x,&y);
        addedge(x,y),addedge(y,x);
    }
    pre(1,0);
    for(int j=1;j<=19;j++)
        for(int i=1;i<=n;i++)
        f[i][j]=f[f[i][j-1]][j-1];
    for(int i=1;i<=n;i++) scanf("%d",&w[i]);
    for(int i=1;i<=m;i++){
        int x,y;scanf("%d%d",&x,&y);
        q[i].from=x,q[i].to=y;val[x]++;
        q[i].lca=Lca(x,y);q[i].len=dep[x]+dep[y]-2*dep[q[i].lca];
        sy1[q[i].lca].push_back(q[i].from);
    }
    dfs1(1,0);
    for(int i=1;i<=m;i++){
        sy2[q[i].to].push_back(dep[q[i].to]-q[i].len);
        sy3[q[i].lca].push_back(dep[q[i].to]-q[i].len);
    }
    dfs2(1,0);
    for(int i=1;i<=m;i++) if(dep[q[i].from]-dep[q[i].lca]==w[q[i].lca]) ans[q[i].lca]--;
    for(int i=1;i<=n;i++) printf("%d ",ans[i]);
    return 0;
}

 

以上是关于NOIP2016天天爱跑步的主要内容,如果未能解决你的问题,请参考以下文章

天天爱跑步[NOIP2016]

NOIP2016天天爱跑步

NOIP2016 天天爱跑步

noip 2016 天天爱跑步

LCA+线段树 NOIP2016 天天爱跑步

NOIP2016天天爱跑步