题目

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

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

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

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

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

输入格式:

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

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

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

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

对于所有的数据,保证 1<=S_i,T_i<=n, 0< W_j <= n , 1≤Si​,Ti​≤n,0≤Wj​≤n 。

输出格式:

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

首先一条链一条链地跑肯定不行,我们想想一个点的答案是怎么被更新的

首先一个点在一个路径上,那么要么这个路径的起点在子树中,要么终点在子树中。

当这个点i被这个路径增加答案时,一定满足:

1 . 起点s在其子树里,那么dep[s] - dep[i] = w[i]

2 . 终点t在其子树里,那么len - (dep[t]-dep[i]) = w[i](len 为路径长度)

整理得到 dep[i] + w[i] =dep[s] , dep[i] - w[i] = dep[t] - len

所以我们要求的就是i子树中满足要求的s,t个数。

发现子树的统计可以递归,用两个桶装 dep[s] ,dep[t] - len 。 求这个点的值时直接从桶里取就好了,而lca为i的路径显然不会对i父亲做出贡献,因此我们在处理完i后将其贡献倒掉

我们先写个dfs的伪代码:

dfs(i )

遍历i的子树

for(每条起点为i的路) 把dep[i]装进桶1

for(每条终点为i的路) 把dep[i] - len装进桶2

ans[i] = 桶1[ dep[i] + w[i] ] + 桶2[ dep[i]-w[i] ]

for(每条lca为i的路)  把这些路的s与t做出的贡献倒掉

最后的小问题   i的兄弟k先于i遍历,所以k的子树的贡献已经装进桶了,我们如何保证i不会被k的子树更新呢?

在遍历i之前先统计一个ans0[i] , 这样ans[i]-ans0[i]就是i子树的贡献了

还有诸多小细节我会在代码中解释

#include <cstdio>
#include <algorithm>
#include <cstring>
int fa[300005][21] ;
int n , m ,w[300005]  ;
int dep[300005],hd[300005] , tot , des[600005] , nxt[600005] , ans[300005];
struct pl{int st , en , lca , len ;
}plan[300005];
int tong1[600005] , tong2[600005] , ans0[300005];//邻接链表实现遍历
int hdst[300005] , ntst[300005] , nust[300005];
void gest ( int x , int num )
{tot++;nust[tot]=num;ntst[tot]=hdst[x];hdst[x]=tot;
}
int hden[300005] , nten[300005] , nuen[300005];
void geen ( int x , int num )
{tot++;nuen[tot]=num;nten[tot]=hden[x];hden[x]=tot;
}
int hdlca[300005] , ntlca[300005] , nulca[300005];
void gelca ( int x , int num )
{tot++;nulca[tot]=num;ntlca[tot]=hdlca[x];hdlca[x]=tot;
}//之后是跑lca
void gw(int x, int y)
{tot++;des[tot] = y;nxt[tot] = hd[x];hd[x] = tot;
}
void dfs(int u,int f)
{for (int k=hd[u];k;k=nxt[k]){int v = des[k];if (v==f)continue ;fa[v][0]=u;dep[v]=dep[u]+1;dfs(v,u);}
}
void yuli( )
{for (int k=1;k<=20;k++)for (int i=1;i<=n;i++)fa[i][k]=fa[fa[i][k-1]][k-1];
}
int lc (int x, int y)
{if(dep[x]<dep[y])std::swap(x,y);int dt=dep[x]-dep[y],ko=0 ;while (dt){if ( dt%2 ) x=fa[x][ko] ;ko++;dt=dt/2;}while (x!=y){int i=0;while(fa[x][i+1]!=fa[y][i+1]){i++;}x=fa[x][i];y=fa[y][i];}return x;
}
void qdfs(int u,int f)//注意dep[u]-w[u]可能下溢,需要平移
{ans0[u] = tong1[dep[u]+w[u]] + tong2[dep[u]-w[u]+300000] ; //之后与伪代码一致for (int k=hd[u];k;k=nxt[k]){int v = des[k];if (v==f)continue ;qdfs(v,u);}for (int k=hdst[u] ; k ; k=ntst[k]) tong1[dep[u]]++;for (int k=hden[u] ; k ; k=nten[k]) tong2[dep[u]-plan[nuen[k]].len+300000] ++; ans[u] = tong1[dep[u]+w[u]] + tong2[dep[u]-w[u]+300000] ;for (int k=hdlca[u] ; k ; k=ntlca[k]){tong1[dep[plan[nulca[k]].st]]--;tong2[dep[plan[nulca[k]].en] - plan[nulca[k]].len+300000]--;}
}
int main()
{freopen("running.in","r",stdin);freopen("running.out","w",stdout);scanf("%d%d",&n,&m);for (int i=1;i<n;i++){int x,y;scanf("%d%d",&x,&y);gw(x,y);gw(y,x);}dfs(1,1);yuli( ) ;for (int i=1;i<=n;i++) scanf("%d",&w[i]);for (int i=1;i<=m;i++){scanf("%d%d",&plan[i].st,&plan[i].en);plan[i].lca = lc ( plan[i].st , plan[i].en ) ;plan[i].len = dep[plan[i].st] + dep[plan[i].en] - 2 * dep[plan[i].lca] ;}tot = 0;for (int i=1;i<=m;i++)gest(plan[i].st,i);tot = 0;for (int i=1;i<=m;i++)geen(plan[i].en,i);tot = 0;for (int i=1;i<=m;i++)gelca(plan[i].lca,i);qdfs (1,1);for (int i=1;i<=m;i++)//当lca恰好能被这条链更新时,这条链的s与t都加了一遍,因此要减去。if ( dep [plan[i].lca] + w[plan[i].lca] == dep[plan[i].st] ) ans[plan[i].lca] -- ;for (int i=1;i<=n;i++)printf("%d ",ans[i]-ans0[i]);
}

noip2016 day1 t2 天天爱跑步相关推荐

  1. 【NOIP 2016】Day1 T2 天天爱跑步

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

  2. NOIP2016·洛谷·天天爱跑步

    初见安~这里是传送门:洛谷P1600 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打 ...

  3. 【NOIP2016】bzoj4719 天天爱跑步

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

  4. [NOIP2016 提高组] 天天爱跑步(树上差分)

    如果没有时间的限制,这题就是对每个点iii,求经过iii的路径数,用树上差分解决即可: 枚举路径x→y{x\to y\{x→y{ a[x]+=1;a[y]+=1;a[x]+=1;a[y]+=1;a[x ...

  5. NOIP2016提高组 天天爱跑步

    (树上差分 + \(LCA\)) \(O(Mlog_2N)\) 调了两个小时,最后发现把\(lca\)里的\(y\)写成\(x\)了,当场去世. 首先下几个定义: \(dis[x]\) 为\(x\)到 ...

  6. [luogu]P1600 天天爱跑步[LCA]

    [luogu]P1600 [NOIP 2016]天天爱跑步 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上 ...

  7. 【NOIP2016提高组】天天爱跑步

    题目背景 NOIP2016 提高组 Day1 T2 题目描述 小 C 同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每 ...

  8. NOIP2016天天爱跑步

    NOIP2016天天爱跑步 这题一看显然lca+树上差分,但是因为有w的限制不能直接加,所以考虑权值线段树合并, 每个选手的起点终点对于不同的节点的影响是不同的,这就非常麻烦了,但是可以发现无论如何他 ...

  9. [NOIP2016]天天爱跑步(lca+乱搞)

    2557. [NOIP2016]天天爱跑步 时间限制:2 s   内存限制:512 MB [题目描述] 小C同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑 ...

最新文章

  1. poj 3255 Roadblocks (SPFA)
  2. java 自适应响应式 网站 源码 SSM 生成 静态化 手机 平板 PC
  3. 1.Linux下libevent和memcached安装
  4. css3实践之图片轮播(Transform,Transition和Animation)
  5. Error: Program type already present: okhttp3.Authenticator$1
  6. 浪潮服务器开启远程管理,浪潮服务器远程管理
  7. C# WPF 定时器
  8. wacom linux 驱动下载,Ubuntu 8.04如何安装WACOM驱动
  9. 物流车辆调度算法matlab,基于遗传算法的预拌混凝土车辆调度优化MATLAB源码
  10. 标准MIDI文件格式
  11. USBKEY用户认证平台的研究和实现
  12. java short 写法_Java Short类shortValue()方法及示例
  13. Codeforces:F - Elongated Matrix
  14. VMware 虚拟机开启Ip地址自动更换解决
  15. Laya.TextInput组件中禁用后改变输入框背景色和文字颜色
  16. 爱快固件是Linux系统吗,Linux 系统下 VirtualBox 里安装爱快系统 (2.4.4)
  17. ae显示不能动态链接服务器,ae pr如何联动、建立动态链接?
  18. 计算机技术与移动支付的关系,移动支付的破与立
  19. 只有170字节,最小的64位Hello World程序这样写成
  20. 微信小程序 请求函数 同步封装方法

热门文章

  1. waning rm -i rm -rvfi
  2. 从程序员角度看“上帝“玩游戏
  3. 《NVMe-over-Fabrics-1_0a-2018.07.23-Ratified》阅读笔记(4)-- Controller Architecture
  4. 华为公有云服务-计算类(2)
  5. 3.飞机机票的价格受季节旺季、淡季的影响,头等舱与经济舱的价格也不同机票的原价为5000,4~10月为旺季, 旺季:头等舱打9折,经济舱打8折;淡季:头等舱打5折,经济舱打4折。请编写根据出行的月份和
  6. 计算机四年级上册语文教案,四年级语文上册的教案
  7. Java Annotation自定义注解详解
  8. webrtc QOS方法十二(接收端IDR帧请求)
  9. 酷客多小程序重磅升级,这十几个模板足以打动你的心!
  10. 2012 r2 万能网卡驱动_6款USB无线网卡评测