noip2016天天爱跑步
题目描述
小c同学认为跑步非常有趣,于是决定制作一款叫做《天天爱跑步》的游戏。«天天爱跑步»是一个养成类游戏,需要玩家每天按时上线,完成打卡任务。
这个游戏的地图可以看作一一棵包含 个结点和
条边的树, 每条边连接两个结点,且任意两个结点存在一条路径互相可达。树上结点编号为从
到
的连续正整数。
现在有个玩家,第
个玩家的起点为
,终点为
。每天打卡任务开始时,所有玩家在第
秒同时从自己的起点出发, 以每秒跑一条边的速度, 不间断地沿着最短路径向着自己的终点跑去, 跑到终点后该玩家就算完成了打卡任务。 (由于地图是一棵树, 所以每个人的路径是唯一的)
小C想知道游戏的活跃度, 所以在每个结点上都放置了一个观察员。 在结点的观察员会选择在第
秒观察玩家, 一个玩家能被这个观察员观察到当且仅当该玩家在第
秒也理到达了结点
。 小C想知道每个观察员会观察到多少人?
注意: 我们认为一个玩家到达自己的终点后该玩家就会结束游戏, 他不能等待一 段时间后再被观察员观察到。 即对于把结点作为终点的玩家: 若他在第
秒重到达终点,则在结点
的观察员不能观察到该玩家;若他正好在第
秒到达终点,则在结点
的观察员可以观察到这个玩家。
输入输出格式
输入格式:
第一行有两个整数和
。其中
代表树的结点数量, 同时也是观察员的数量,
代表玩家的数量。
接下来 行每行两个整数
和
,表示结点
到结点
有一条边。
接下来一行 个整数,其中第
个整数为
, 表示结点
出现观察员的时间。
接下来 行,每行两个整数
,和
,表示一个玩家的起点和终点。
对于所有的数据,保证 。
输出格式:
输出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
2 0 0 1 1 1
5 3
1 2
2 3
2 4
1 5
0 1 0 3 0
3 1
1 4
5 5
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天天爱跑步的更多相关文章
- [NOIp2016]天天爱跑步 线段树合并
[NOIp2016]天天爱跑步 LG传送门 作为一道被毒瘤出题人们玩坏了的NOIp经典题,我们先不看毒瘤的"动态爱跑步"和"天天爱仙人掌",回归一下本来的味道. ...
- [Noip2016]天天爱跑步 LCA+DFS
[Noip2016]天天爱跑步 Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要玩家每天按时上线,完成打卡任 ...
- 【LG1600】[NOIP2016]天天爱跑步
[LG1600][NOIP2016]天天爱跑步 题面 洛谷 题解 考虑一条路径\(S\rightarrow T\)是如何给一个观测点\(x\)造成贡献的, 一种是从\(x\)的子树内出来,另外一种是从 ...
- NOIP2016天天爱跑步 题解报告【lca+树上统计(桶)】
题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 nn个 ...
- BZOJ4719 [Noip2016]天天爱跑步
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转 ...
- bzoj 4719: [Noip2016]天天爱跑步
Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要 玩家每天按时上线,完成打卡任务.这个游戏的地图可以看作一一 ...
- NOIP2016 天天爱跑步 80分暴力
https://www.luogu.org/problem/show?pid=1600 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养 ...
- 4719: [Noip2016]天天爱跑步
Time Limit: 40 Sec Memory Limit: 512 MB Submit: 1986 Solved: 752 [Submit][Status][Discuss] Descripti ...
- NOIP2016 天天爱跑步 线段树合并_桶_思维题
竟然独自想出来了,好开心 Code: #include<bits/stdc++.h> #define setIO(s) freopen(s".in","r&q ...
随机推荐
- 【记录】haphost免费vps初始配置
1.配置德国epel源 yum install yum-priorities rpm -Uvh http://ftp-stud.hs-esslingen.de/pub/epel/6/i386/epel ...
- 修改sqlserver的数据库排序规则语句
alter database SOETMS collate Chinese_PRC_CI_AS
- [转]JSON详解
阅读目录 JSON的两种结构 认识JSON字符串 在JS中如何使用JSON 在.NET中如何使用JSON 总结 JSON的全称是”JavaScript Object Notation”,意思是Java ...
- HDU 3183 A Magic Lamp(二维RMQ)
第一种做法是贪心做法,只要前面的数比后面的大就把他删掉,这种做法是正确的,也比较好理解,这里就不说了,我比较想说一下ST算法,RMQ的应用 主要是返回数组的下标,RMQ要改成<=(这里是个坑点, ...
- Shortest Path
Shortest Path Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)T ...
- Django之路: 基本命令与网址进阶
一.Django 基本命令 温馨提示:如果你想学习Django,那么就请您从现在开始按照笔记记录一步一步的用手把代码敲出来,千万不要偷懒哦..... 1.创建一个Django project djan ...
- android bitmap compress(图片压缩)
android bitmap compress android的照相功能随着手机硬件的发展,变得越来越强大,能够找出很高分辨率的图片. 有些场景中,需要照相并且上传到服务,但是由于图片的大小太大,那么 ...
- Android MulticastSocket IP组播
MulticastSocket是对等的关系,也就是他们通过IP多点组播保留的地址来相互接收在这个组的Socket发送的消息 我写了一个例子,MultiSocketB是一个service,用于先接收再发 ...
- Openlayers修改矢量要素
将以下代码放到demo下examples中即可运行 <!DOCTYPE html><html> <head> <meta http-equiv="C ...
- js Date 日期格式化(转)
var myDate = new Date();myDate.getYear(); //获取当前年份(2位)myDate.getFullYear(); //获取完整的年份(4位,1 ...