题目大意:
  有一棵n个点的树,每个点上有一个摄像头会在第w[i]秒拍照。
  有m个人再树上跑,第i个人沿着s[i]到t[i]的路径跑,每秒钟跑一条边。
  跑到t[i]的下一秒,人就会消失。
  问每个摄像头会拍下几个人。

思路:
  首先很显然是要求LCA的。
  求完LCA怎么办?
  我们可以用树上差分的方法分别维护向上、向下的链。
  每一条路径,我们可以在s,t,lca,par[lca]上分别打标记。
  s +dep[s]
  t +dep[t]-len
  lca -dep[s]
  par[lca] +len-dep[t]
  其中有一些是向上走的链、有一些是向下走的链,因此我们还需要将它们区分开来。
  一个点x满足条件当且仅当x在s到lca的路上且dep[x]-dep[s]=w[x],
  或者x在lca到t的路上且dep[lca]-dep[s]+deo[lca]-dep[x]=w[x]。
  最后从根节点DFS统计一下,访问到x结点就把对应的标记加进去,ans[x]=统计完子树后的答案-统计之前的答案。
  另外注意dep[t]-len可能会是负的,因此我们可以将它们整体往右移一些位置。

 #include<cstdio>
#include<cctype>
#include<vector>
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'';
while(isdigit(ch=getchar())) x=(((x<<)+x)<<)+(ch^'');
return x;
}
const int N=,logN=;
std::vector<int> e[N];
inline void add_edge(const int &u,const int &v) {
e[u].push_back(v);
e[v].push_back(u);
}
int w[N],dep[N],anc[N][logN];
inline int log2(const float &x) {
return ((unsigned&)x>>&)-;
}
void dfs(const int &x,const int &par) {
dep[x]=dep[par]+;
anc[x][]=par;
for(register int i=;i<=log2(dep[x]);i++) {
anc[x][i]=anc[anc[x][i-]][i-];
}
for(register unsigned i=;i<e[x].size();i++) {
const int &y=e[x][i];
if(y==par) continue;
dfs(y,x);
}
}
inline int lca(int x,int y) {
if(dep[x]<dep[y]) std::swap(x,y);
for(register int i=log2(dep[x]-dep[y]);i>=;i--) {
if(dep[anc[x][i]]>=dep[y]) {
x=anc[x][i];
}
}
if(x==y) return x;
for(register int i=log2(dep[x]);i>=;i--) {
if(anc[x][i]!=anc[y][i]) {
x=anc[x][i];
y=anc[y][i];
}
}
return anc[x][];
}
struct Tag {
bool type;
int val,sgn;
};
std::vector<Tag> tag[N];
int ans[N];
int cnt1[N<<],cnt2[N<<];
void stat(const int &x) {
const int tmp=cnt1[dep[x]+w[x]]+cnt2[dep[x]-w[x]+(N<<)];
for(register unsigned i=;i<tag[x].size();i++) {
const Tag &t=tag[x][i];
(t.type?cnt1:cnt2)[t.val]+=t.sgn;
}
for(unsigned i=;i<e[x].size();i++) {
const int &y=e[x][i];
if(y==anc[x][]) continue;
stat(y);
}
ans[x]=cnt1[dep[x]+w[x]]+cnt2[dep[x]-w[x]+(N<<)]-tmp;
}
int main() {
const int n=getint(),m=getint();
for(register int i=;i<n;i++) {
add_edge(getint(),getint());
}
for(register int i=;i<=n;i++) {
w[i]=getint();
}
dfs(,);
for(register int i=;i<m;i++) {
const int s=getint(),t=getint(),p=lca(s,t),len=dep[s]+dep[t]-(dep[p]<<);
tag[s].push_back((Tag){,dep[s],});
tag[t].push_back((Tag){,dep[t]-len+(N<<),});
tag[p].push_back((Tag){,dep[s],-});
tag[anc[p][]].push_back((Tag){,dep[t]-len+(N<<),-});
}
stat();
for(register int i=;i<n;i++) {
printf("%d ",ans[i]);
}
printf("%d",ans[n]);
return ;
}

[NOIp2016提高组]天天爱跑步的更多相关文章

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

    对于一条路径,s-t,位于该路径上的观察员能观察到运动员当且仅当以下两种情况成立:(d[ ]表示节点深度) 1.观察员x在s-lca(s,t)上时,满足d[s]=d[x]+w[x]就能观察到,所以我们 ...

  2. NOIP2016提高组解题报告

    NOIP2016提高组解题报告 更正:NOIP day1 T2天天爱跑步 解题思路见代码. NOIP2016代码整合

  3. 【题解】NOIP2016提高组 复赛

    [题解]NOIP2016提高组 复赛 传送门: 玩具谜题 \(\text{[P1563]}\) 天天爱跑步 \(\text{[P1600]}\) 换教室 \(\text{[P1850]}\) 组合数问 ...

  4. 【题解】NOIP2016 提高组 简要题解

    [题解]NOIP2016 提高组 简要题解 玩具迷题(送分) 用异或实现 //@winlere #include<iostream> #include<cstdio> #inc ...

  5. [NOIP2016 DAY1 T2]天天爱跑步-[差分+线段树合并][解题报告]

    [NOIP2016 DAY1 T2]天天爱跑步 题面: B[NOIP2016 DAY1]天天爱跑步 时间限制 : - MS 空间限制 : 565536 KB 评测说明 : 2s Description ...

  6. BZOJ4719[NOIP2016提高组Day1T2] 天天爱跑步

    #261. [NOIP2016]天天爱跑步 描述 提交 自定义测试 小C同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家 ...

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

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

  8. Luogu P1600[NOIP2016]day1 T2天天爱跑步

    号称是noip2016最恶心的题 基本上用了一天来搞明白+给sy讲明白(可能还没讲明白 具体思路是真的不想写了(快吐了 如果要看,参见洛谷P1600 天天爱跑步--题解 虽然这样不好但我真的不想写了 ...

  9. [日记&做题记录]-Noip2016提高组复赛 倒数十天

    写这篇博客的时候有点激动 为了让自己不颓 还是写写日记 存存模板 Nov.8 2016 今天早上买了两个蛋挞 吃了一个 然后就做数论(前天晚上还是想放弃数论 但是昨天被数论虐了 woc noip模拟赛 ...

随机推荐

  1. js_setCookie,getCookie和checkcookie函数

    随便说说: cookie和sessionStrong,localStrong在web应用中都有一种存储的功能,也就是说可以把一些数据记录在浏览器.cookie和后两者的主要区别 是cookie是和后端 ...

  2. promise 如何知道所有的回调都执行完了?

    var fs = require('fs'); /** * @return {object} Promise */ function doThing(fileName) { // ... // con ...

  3. vue-实现倒计时功能

    JavaScript 创建一个 countdown 方法,用于计算并在控制台打印距目标时间的日.时.分.秒数,每隔一秒递归执行一次. msec 是当前时间距目标时间的毫秒数,由时间戳相减得到,我们将以 ...

  4. Android 6.0 Marshmallow root 方法

    android 6.0 已经推出 release 版本了, nexus 5,6,7,9 都放了官方镜像, 本篇文章使用 nexus 6 安装最新的 android 6.0 并进行root step 1 ...

  5. python基础===discover函数介绍

    discover(start_dir,pattern='test*.py',top_level_dir=None) 找到指定目录下所有测试模块,并可递归查到子目录下的测试木块,只有匹配到的文件名才会被 ...

  6. Memcached内存缓存技术

    Memcached是什么,有什么作用? Memcached是一个开源的.高性能的内存缓存软件,从名称上看Mem就是内存的意思,而Cache就是缓存的意思. Memcached通过在事先规划好的内存空间 ...

  7. java的关键字final

    final可以修饰类,成员方法,成员变量. 1.final修饰的类不能被继承,所以没有子类 final class First{ int num; } class Second extends Fir ...

  8. experss 做小型服务器出现跨域问题

    情况是这样的 我用express做一个小型的服务器来做我demo项目的一个接口 然后我就出现了跨域问题 然后我就 app.all('/*', function(req, res, next) { // ...

  9. 《java并发编程实战》读书笔记11--构建自定义的同步工具,条件队列,Condition,AQS

    第14章 构建自定义的同步工具 本章将介绍实现状态依赖性的各种选择,以及在使用平台提供的状态依赖机制时需要遵守的各项规则. 14.1 状态依赖性的管理 对于并发对象上依赖状态的方法,虽然有时候在前提条 ...

  10. python调用.so

    python调用动态链接库的基本过程 动态链接库在Windows中为.dll文件,在linux中为.so文件.以linux平台为例说明python调用.so文件的使用方法. 本例中默认读者已经掌握动态 ...