题面传送门

解答

设第\(j\)号玩家在\(V_j\)时刻出发。

弱化问题:如果树退化成了一条链。则在\(j\)处的观察员能观察到的\(i\)号玩家当且仅当

\[i玩家经过j,且
\begin{cases}
dep_j - W_j = dep_{S_i} - V_j, &i向下跑步 \\
dep_j + W_j = dep_{S_i} + V_j, &i向上跑步
\end{cases}
\]

一个点在树上的贡献是连续的,可以考虑把路径在LCA处(倍增找LCA)拆成两条链用离线+树上差分统计人经过每个点的时刻。

树上差分

如何只让一段树上的链被更新呢?(类比左闭右开区间,考虑下端为“闭”节点,上端为“开”节点的链)

考虑树上的一个点,只有链的一端在它的子树内部时才被链覆盖。

所以在dfs子树之前记下答案,在dfs之后更新链端点,实际的答案就是答案的差。

#include <bits/stdc++.h>
using namespace std; const int mx = 3e5+10, LOG = 20, inf = 1e9; int n, m, ans[mx], s[mx], t[mx], w[mx];
int head[mx], nxt[mx<<1], to[mx<<1], tot;
int dep[mx] = {-1}, fa[mx][LOG];
int down[mx<<2], up[mx<<1];
vector<pair<int, int> > v[mx]; void add(int u, int v) {
++tot;
nxt[tot] = head[u];
to[tot] = v;
head[u] = tot;
} void dfs0(int u) {
for (int i = 1; i < LOG; ++i) {
fa[u][i] = fa[fa[u][i-1]][i-1];
}
for (int e = head[u], v; e; e = nxt[e]) {
if ((v=to[e]) == fa[u][0]) continue;
fa[v][0] = u;
dep[v] = dep[u]+1;
dfs0(v);
}
} int lca(int u, int v) {
if (dep[u] < dep[v]) swap(u, v);
for (int i = LOG-1; ~i; --i)
if (dep[fa[u][i]] >= dep[v])
u = fa[u][i];
if (u == v) return u;
for (int i = LOG-1; ~i; --i)
if (fa[u][i] != fa[v][i])
u = fa[u][i], v = fa[v][i];
return fa[u][0];
} #define pb push_back
#define mp make_pair
#define fi first
#define se second void addr(int s, int t, int w=0) {
assert(dep[s] != dep[t]);
if (dep[s] < dep[t]) w += inf, swap(s, t);
v[s].pb(mp(w, 1));
v[t].pb(mp(w, -1));
} void dfs(int u) {
ans[u] -= up[dep[u]+w[u]] + down[(mx<<1) + dep[u]-w[u]];
for (int e = head[u]; e; e = nxt[e]) {
if (to[e] == fa[u][0]) continue;
dfs(to[e]);
}
for (int i = 0; i < (int)v[u].size(); ++i) {
if (v[u][i].fi > inf/2) down[(mx<<1) + v[u][i].fi-inf] += v[u][i].se;
else up[v[u][i].fi] += v[u][i].se;
}
ans[u] += up[dep[u]+w[u]] + down[(mx<<1) + dep[u]-w[u]];
} int main() {
scanf("%d%d", &n, &m);
int u, v;
for (int i = 0; i < n-1; ++i) {
scanf("%d%d", &u, &v);
add(u, v), add(v, u);
}
dfs0(1);
for (int i = 1; i <= n; ++i) scanf("%d", w+i);
for (int i = 1; i <= m; ++i) {
scanf("%d%d", s+i, t+i);
u = lca(s[i], t[i]);
if (u == s[i]) addr(fa[s[i]][0], t[i], dep[s[i]]);
else if (u == t[i]) addr(s[i], fa[t[i]][0], dep[s[i]]);
else {
addr(s[i], fa[u][0], dep[s[i]]);
addr(u, t[i], dep[u] - (dep[s[i]]-dep[u]));
}
}
dfs(1);
for (int i = 1; i <= n; ++i) printf("%d%c", ans[i], " \n"[i==n]);
}

[NOIP2016]天天爱跑步-题解的更多相关文章

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

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

  2. [NOIP2016]天天爱跑步 题解(树上差分) (码长短跑的快)

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

  3. 「NOIP2016」天天爱跑步 题解

    (声明:图片来源于网络) 「NOIP2016」天天爱跑步 题解 题目TP门 题目 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是 ...

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

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

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

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

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

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

  7. Noip 2016 天天爱跑步 题解

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

  8. [luogu1600 noip2016] 天天爱跑步 (树上差分)

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

  9. BZOJ4719 [Noip2016]天天爱跑步

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

随机推荐

  1. 【luoguP2989】[USACO10MAR]对速度的需要Need For Speed

    题目描述 最大化平均值 二分一个\(x\) \(check\): \(\frac{F+\sum_{i=1}^{n} X_{i} \times F_{i}}{M+\sum_{i=1}^{n} X_{i} ...

  2. npm link 的用法

    npm link 的用法 先到对应的自定义包下执行 npm link 会读取对应的 packagejson 中的名称 然后到对应的目录下执行 npm link your/own/npm/name 就会 ...

  3. JavaScript map reduce

    23333333333333 map var s = []; for(let i=0;i<10;i++){ s.push(i); } function pow(x){ return x*x; } ...

  4. 内核过DSE驱动签名验证.

    一丶简介 现在的驱动,必须都有签名才能加载.那么如何加载无签名的驱动模块那. 下面可以说下方法.但是挺尴尬的是,代码必须在驱动中编写.所以就形成了 你必须一个驱动带有一个签名加载进去.执行你的代码.p ...

  5. JMeter的基本使用

    什么是Jmeter JMeter是Apache基于Java开发的压力测试工具,通俗的说,你想知道你的接口有多猛,你的服务器是否耐揍,这个家伙可以用数据告诉你.原来学过JMeter的基本使用,发现想不起 ...

  6. ex1

    #include <stdio.h> int main() { int x; printf("输入一个整数: \n"); scanf("%d",&a ...

  7. 分布式系统 与 Google

    google 论文 http://duanple.com/?p=170 google 论文与开源 http://duanple.com/?p=1096 分布式系统论文集 https://github. ...

  8. Java多次启动相同jar程序

    背景 现在很多软件都支持集群部署,但是测试环境通常资源有限,所以一般通过单台机器模拟集群部署(使用不同端口,运行相同jar包),本文的目的就是通过多种方式实现此需求. 两个程序 1.jar程序 ① s ...

  9. MyBatis(十):Mybatis 几种批量操作的对比

    本章主要讲解几种批量处理的用法及对别,批量处理一般用法包含以下几种: 1)普通foreach处理(没循环一次执行一次与mysql服务器交互操作),实际上也是采用的ExecutorType.SIMPLE ...

  10. Mini UI tree上万复杂节点加载缓慢处理设计

    最直接的方式是设置tree顶级不展开,可以解决一定效率. expandOnLoad Boolean/Number 加载后是否展开.比如:true展开所有节点:0展开第一级节点.以此类推. 1. 解决问 ...