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 ...
随机推荐
- localStorage、sessionStorages 使用
html5中的Web Storage包括了两种存储方式:sessionStorage和localStorage.sessionStorage用于本地存储一个会话(session)中的数据,这些数据只有 ...
- Python中super的用法
super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO).重复调用(钻石继承)等种种问题.总之前人留下的经验就是:保持一致性 ...
- Delph组件如何使用自己的图标(转)
源:http://blog.csdn.net/henreash/article/details/7298451
- 计算机学院大学生程序设计竞赛(2015’12) 1005 Bitwise Equations
#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using ...
- Java谜题——库谜题
1.Java中的不可变对象和可变对象 (1)不可变类:当你获得这个类的实例的引用之后,你不可以改变这个实例的内容.比如:String,BigInteger,BigDecimal,还有基本数据类型的封装 ...
- Hibernate---O/R Mapping
1. JDBC数据库繁琐 2. sql语句不是面向对象 3. 可以在对象和关系表之间建立关联简化编程 4. O/R Mapping可以简化编程, 跨越数据库平台 比较流行的O/R Mapping Fr ...
- 用css制作一个三角形箭头
剑走偏锋——用css制作一个三角形箭头 通常,我们做上图那个三角形,一般都是做张图,而且需要两张,因为一般都是下拉菜单的效果,需要有个hover的样式,箭头是反的.那是不是有更好的办法呢,毕竟要用 ...
- Xcode的管理工具
Xcode插件管理工具Alcatraz Alcatraz 1.简介 Alcatraz是一个能帮你管理Xcode插件丶模版及颜色配置的工具.它可以直接集成在Xcode的图形界面中,让你感觉就像在使用Xc ...
- STM8S awu及看门狗IWDG WWDG应用(转)
源:STM8S awu及看门狗IWDG WWDG应用 AWU的应用(用库函数完成的) //切记要开启中断 且在中断函数中 AWU_GetFlagStatus(); 来清除中断 void AWU_SET ...
- python遍历字典元素
a={'a':{'b':{'c':{'d':'e'}},'f':'g'},'h':'i'} def show(myMap): for str in myMap.keys(): secondDict=m ...