题目描述

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

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

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

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

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

输入输出格式

输入格式:

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

接下来 行每行两个整数,表示结点 到结点 有一条边。

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

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

对于所有的数据,保证

输出格式:

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

输入输出样例

输入样例#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说明】

对于1号点,,故只有起点为1号点的玩家才会被观察到,所以玩家1和玩家2被观察到,共有2人被观察到。

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

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

对于4号点,玩家1被观察到,共1人被观察到。

对于5号点,玩家1被观察到,共1人被观察到。

对于6号点,玩家3被观察到,共1人被观察到。

【子任务】

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

【提示】

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

这道题的25分可以直接暴力得到。

对于15分链状的情况,我们可以设一个不定长数组对于每个点的观察员观察时间t在所在点向左t点打标记,向右t点打标记即可。然后对于每组起点与终点,查看起点不定长数组的所在位置是否在起点和终点之间。

对于20分起点为1的情况,以1为根,所有经过时间一定是深度,所以做一个桶即可。

对于20分终点为1的情况,同样以1为根,每个点i能观察到的路径起点u一定保证dep[u]=dep[i]-time[i];time[i]表示观察时间首先做一个桶,将起点放入,之后设一个关于深度的桶,对于每个点i的答案只需知道cnt[dep[u]+time[i]]在遍历前后的变化值即可。

80分代码:

#include<cstdio>
#include<vector>
using namespace std;
const int N=;
struct X
{
int v,f,n;
}x[N<<];
int dep[N],s,fa[N],ti[N],tong[N];
vector<int>lian[N];
void add(int u,int v)
{
x[++s].n=x[u].f;
x[x[u].f=s].v=v;
}
void dfs(int u)
{
for(int i=x[u].f;i;i=x[i].n)
if(x[i].v!=fa[u])
dep[x[i].v]=dep[fa[x[i].v]=u]+,dfs(x[i].v);
}
int lca(int u,int v)
{
while(u!=v)
if(dep[u]>=dep[v]) u=fa[u];
else v=fa[v];
return u;
}
void ju(int u,int v,int tv)
{
int tu=;
if(!ti[u]) tong[u]++;
if(u!=v&&ti[v]==tv) tong[v]++;
while(u!=v)
if(dep[u]>=dep[v])
{
u=fa[u];
++tu;
if(tu==ti[u]&&u!=v) ++tong[u];
}
else
{
v=fa[v];
--tv;
if(tv==ti[v]&&u!=v) ++tong[v];
}
return;
}
void dfs2(int u)
{
for(int i=x[u].f;i;i=x[i].n)
if(x[i].v!=fa[u])
fa[x[i].v]=u,dep[x[i].v]=dep[u]+,dfs2(x[i].v),tong[u]+=tong[x[i].v];
}
int main()
{
//freopen("running.in","r",stdin),freopen("running.out","w",stdout);
int n,m;
scanf("%d%d",&n,&m);
for(int i=;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v);add(v,u);
}
for(int i=;i<=n;i++) scanf("%d",&ti[i]);
if(n==)
{
for(int i=;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
++tong[v];
}
dfs2();
for(int i=;i<=n;i++)
if(dep[i]==ti[i]) printf("%d ",tong[i]);
else printf("0 ");
}
else if(n==)
{
for(int i=;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
lian[u].push_back(v);
}
for(int i=;i<=n;i++)
{
int ans=;
if(ti[i]<i)
{
int len=lian[i-ti[i]].size();
for(int j=;j<len;j++)
if(lian[i-ti[i]][j]>=i) ans++;
}
if(ti[i]+i<=n)
{
int len=lian[ti[i]+i].size();
for(int j=;j<len;j++)
if(lian[ti[i]+i][j]<i||(lian[ti[i]+i][j]==i&&ti[i])) ans++;
}
printf("%d ",ans);
}
}
else if(n<=)
{
dfs();
for(int i=;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
int t=lca(u,v),dis=dep[u]+dep[v]-*dep[t];
ju(u,v,dis);
}
for(int i=;i<=n;i++)
printf("%d ",tong[i]);
}
return ;
}

100分:

链上算法都有了,树上算法还远吗?

我们把每条路径拆成从u到lca和lca到v的两条路径。(对于原本就是链的路径特判,并且非链的lca可能会多算要减去1)

1.统计u到lca的路径:与上文中以一为终点的方法相似,对于一个点a它所能观察到的点的深度应为dep[a]+time[a],所以我们同样用桶作记录。对于一条路径我们在离开u点时给dep[u]++,

离开lca时给dep[u]--;

2.统计lca到v的路径时,只是将所改的深度变为dep[lca]*2-dep[u],因为这个值可能小于0所以加上最大值。

#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int N=;
struct X
{
int v,f,n;
}x[N<<],y[N<<];
vector<int>ad1[N],ad2[N],de1[N],de2[N];
int dep[N],s,ti[N],to1[N],to2[N<<],n,ans[N],lc[N];
void add(int u,int v,X *t)
{
t[++s].n=t[u].f;
t[t[u].f=s].v=v;
}
int find(int a)
{
int b=a;
while(to1[b]) b=to1[b];
while(b!=a)
{
int t=to1[a];
to1[a]=b;
a=t;
}
return b;
}
void dfs1(int u,int fa)
{
for(int i=x[u].f;i;i=x[i].n)
if(x[i].v!=fa)
{
dep[x[i].v]=dep[u]+;
dfs1(x[i].v,u);
to1[x[i].v]=u;
}
for(int i=y[u].f;i;i=y[i].n)
if(y[i].v==||dep[y[i].v]) lc[i>>]=find(y[i].v);
}
void dfs2(int u,int fa)
{ if(dep[u]+ti[u]<=n) ans[u]-=to1[dep[u]+ti[u]];
if(ti[u]<=n) ans[u]-=to2[N+dep[u]-ti[u]];
for(int i=x[u].f;i;i=x[i].n)
if(x[i].v!=fa) dfs2(x[i].v,u);
for(int i=;i<ad2[u].size();i++) ++to2[ad2[u][i]];
if(ti[u]<=n) ans[u]+=to2[N+dep[u]-ti[u]];
for(int i=;i<de2[u].size();i++) --to2[de2[u][i]];
for(int i=;i<ad1[u].size();++i) ++to1[ad1[u][i]];
if(dep[u]+ti[u]<=n) ans[u]+=to1[dep[u]+ti[u]];
for(int i=;i<de1[u].size();++i) --to1[de1[u][i]];
}
int main()
{
int m;
scanf("%d%d",&n,&m);
for(int i=;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v,x);add(v,u,x);
}
for(int i=;i<=n;++i) scanf("%d",&ti[i]);
s=;
for(int i=;i<=m;++i)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v,y);add(v,u,y);
}
dfs1(,);
memset(to1,,sizeof(to1));
for(int i=;i<=m;++i)
{
int u=y[i<<|].v,v=y[i<<].v;
if(lc[i]==v)
{
ad1[u].push_back(dep[u]);
de1[v].push_back(dep[u]);
}
else if(lc[i]==u)
{
de2[u].push_back(dep[u]+N);
ad2[v].push_back(dep[u]+N);
}
else
{
ad1[u].push_back(dep[u]);
de1[lc[i]].push_back(dep[u]);
de2[lc[i]].push_back((dep[lc[i]]<<)-dep[u]+N);
ad2[v].push_back((dep[lc[i]]<<)-dep[u]+N);
if(dep[lc[i]]+ti[lc[i]]==dep[u]) --ans[lc[i]];
}
}
dfs2(,);
for(int i=;i<=n;i++)
printf("%d ",ans[i]);
return ;
}

noip2016天天爱跑步的更多相关文章

  1. [NOIp2016]天天爱跑步 线段树合并

    [NOIp2016]天天爱跑步 LG传送门 作为一道被毒瘤出题人们玩坏了的NOIp经典题,我们先不看毒瘤的"动态爱跑步"和"天天爱仙人掌",回归一下本来的味道. ...

  2. [Noip2016]天天爱跑步 LCA+DFS

    [Noip2016]天天爱跑步 Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要玩家每天按时上线,完成打卡任 ...

  3. 【LG1600】[NOIP2016]天天爱跑步

    [LG1600][NOIP2016]天天爱跑步 题面 洛谷 题解 考虑一条路径\(S\rightarrow T\)是如何给一个观测点\(x\)造成贡献的, 一种是从\(x\)的子树内出来,另外一种是从 ...

  4. NOIP2016天天爱跑步 题解报告【lca+树上统计(桶)】

    题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 nn个 ...

  5. BZOJ4719 [Noip2016]天天爱跑步

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转 ...

  6. bzoj 4719: [Noip2016]天天爱跑步

    Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要 玩家每天按时上线,完成打卡任务.这个游戏的地图可以看作一一 ...

  7. NOIP2016 天天爱跑步 80分暴力

    https://www.luogu.org/problem/show?pid=1600 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养 ...

  8. 4719: [Noip2016]天天爱跑步

    Time Limit: 40 Sec Memory Limit: 512 MB Submit: 1986 Solved: 752 [Submit][Status][Discuss] Descripti ...

  9. NOIP2016 天天爱跑步 线段树合并_桶_思维题

    竟然独自想出来了,好开心 Code: #include<bits/stdc++.h> #define setIO(s) freopen(s".in","r&q ...

随机推荐

  1. GB2312转unicode程序(转)

     GB2312转unicode程序   #ifndef UNICODE_H #define UNICODE_H #include <string.h> #ifdef __DEFLINUX_ ...

  2. IE6里面display:inlineblock使得块元素成行排列,没用

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  3. Python3基础 list(enumerate()) 将一个列表的每一个元素转换成 带索引值的元组

    镇场诗: 诚听如来语,顿舍世间名与利.愿做地藏徒,广演是经阎浮提. 愿尽吾所学,成就一良心博客.愿诸后来人,重现智慧清净体.-------------------------------------- ...

  4. 需要注意的subList方法!和substring是不一样的!从源码解释他们的不同。

    很多时候我们截取字符串用的是substring方法,很自然用着,但是对于列表的截取时很多时候就用得很少,但是其实他们是很不一样的,具体哪里不一样呢? package main; import java ...

  5. STM32开发指南-DMA

    DMA,直接存储器访问.传输数据时,外设通过DMA控制器直接访问内存,不经过cpu直接控制传输数据.不需要像中断处理方式需要保留和恢复现场的过程.通过硬件为内存和I/O设备开辟一条直接传送数据的通道, ...

  6. PHP json不转义

    json_encode($result, JSON_UNESCAPED_UNICODE);

  7. C++------------typedef 函数指针类型定义

    摘要bycrazyhacking:        typedef 是定义了一种"函数指针"类型,可以再声明很多变量.函数指针的定义是定义了一个变量. int max(int x,i ...

  8. SQL truncate 、delete与drop区别

    SQL truncate .delete与drop区别 相同点: 1.truncate和不带where子句的delete.以及drop都会删除表内的数据. 2.drop.truncate都是DDL语句 ...

  9. CodeForces 621C Wet Shark and Flowers

    方法可以转化一下,先计算每一个鲨鱼在自己范围内的数能被所给素数整除的个数有几个,从而得到能被整除的概率,设为f1,不能被整除的概率设为f2. 然后计算每相邻两只鲨鱼能获得钱的期望概率,f=w[id1] ...

  10. Sencha Cmd的简介

    Sencha Cmd的简介 ~~~~~~~~~~~~~~~~~~~~~~~ Sencha cmd 是一个跨平台的命令行工具,它从你应用程序的新创建到部署入产品中的整个生命周期都提供了许多自动化的执行任 ...