题面

​ 直接写正解吧, 不想再写部分分了, 对于\(u\)和\(v\), 我们可以将它拆成两条路径, \(u\)到\(lca(u, v)\)和\(lca(u, v)\)到v, 在这里只分析从\(u\)到\(lca(u, v)\)的路径(其实是我不想写).

​ 对于一个点\(u\), 设它的深度为\(dep[u]\), 值为\(dep[i] + w[i]\)的物品有\(cnt[w[i] + dep[i]]\)个, 这样的话, 只有在满足\(dep[u] - dep[i] = w[i]\)的时候, 才能对这个点产生贡献, 由于这三个数都是确定的, 所以在某个起点出发到一个终点结束的路径, 我们处理出他的lca后, 可以使用树上差分, 将一个值为\(dep[u]\)的物品从\(u\)传入, 从\(lca(u, v)\)的父亲传出, 这样就可以对每个点进行树上差分, 在插入之前记录一下\(cnt[w[i] + dep[i]]\)的物品有多少个, 再从底往上更新, 查询当前点\(dep[i] + w[i]\)的物品有多少个, 相减即可.

​ 至于\(lca(u, v)\)的情况, 大家根据上面列一个式子用同样的方法判断就行了, 这里只列出式子, 大家也可以自己推导一下, 最后是这个样子\(dep[u] + dep[i] - 2 * dep[lca(u, v)] = w[i]\), 有可能等式左边的会小于零, 在数组上平移一段即可.

具体代码

#include <iostream>
#include <cstdio>
#include <vector>
#define N 300005
using namespace std; int n, m, w[N], head[N], cnt, f[N][20], dep[N], num[N], c1[N], c2[N << 1];
struct node
{
int to, next;
} edge[N << 1];
vector<int> lin[N], lout[N], rin[N], rout[N]; inline int read()
{
int x = 0, w = 1;
char c = getchar();
while(c < '0' || c > '9') { if (c == '-') w = -1; c = getchar(); }
while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
return x * w;
} inline void add(int u, int v) { edge[++cnt].to = v; edge[cnt].next = head[u]; head[u] = cnt; } void dfs(int u, int fa)
{
dep[u] = dep[fa] + 1;
for(int i = 1; i <= 18 && f[f[u][i - 1]][i - 1]; i++)
f[u][i] = f[f[u][i - 1]][i - 1];
for(int i = head[u]; i; i = edge[i].next)
{
int v = edge[i].to; if(v == fa) continue;
f[v][0] = u; dfs(v, u);
}
} int LCA(int u, int v)
{
if(dep[u] > dep[v]) swap(u, v);
for(int i = 18; i >= 0; i--)
if(dep[f[v][i]] >= dep[u]) v = f[v][i];
if(v == u) return u;
for(int i = 18; i >= 0; i--)
if(f[u][i] != f[v][i]) { u = f[u][i]; v = f[v][i]; }
return f[u][0];
} void down(int u)
{
int sum1 = c1[w[u] + dep[u]], sum2 = c2[w[u] - dep[u] + 300000];
for(int i = head[u]; i; i = edge[i].next)
if(edge[i].to != f[u][0]) down(edge[i].to);
for(unsigned int i = 0; i < lin[u].size(); i++) c1[lin[u][i]]++;//记录一下
for(unsigned int i = 0; i < lout[u].size(); i++) c1[lout[u][i]]--;
for(unsigned int i = 0; i < rin[u].size(); i++) c2[rin[u][i] + 300000]++;
for(unsigned int i = 0; i < rout[u].size(); i++) c2[rout[u][i] + 300000]--;//记得平移
num[u] += c1[w[u] + dep[u]] - sum1 + c2[w[u] - dep[u] + 300000] - sum2; //相减即为答案
} int main()
{
n = read(); m = read();
for(int i = 1; i < n; i++)
{
int u = read(), v = read();
add(u, v); add(v, u);
}
for(int i = 1; i <= n; i++) w[i] = read();
dfs(1, 0);
for(int i = 1; i <= m; i++)
{
int u = read(), v = read();
int lca = LCA(u, v);
lin[u].push_back(dep[u]); lout[f[lca][0]].push_back(dep[u]); rin[v].push_back(dep[u] - 2 * dep[lca]); rout[lca].push_back(dep[u] - 2 * dep[lca]); //u到lca和lca到v, 由于lca已经走过, 这个时候从lca传入就相当于这个物品是在lca与v那条链上lca的儿子传入, 差分嘛
}
down(1);
for(int i = 1; i <= n; i++) printf("%d%c", num[i], i == n ? '\n' : ' ');
return 0;
}

[luogu1600] 天天爱跑步的更多相关文章

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

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

  2. UOJ261 【NOIP2016】天天爱跑步

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

  3. BZOJ4719 [Noip2016]天天爱跑步

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

  4. noip2016天天爱跑步

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

  5. bzoj 4719: [Noip2016]天天爱跑步

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

  6. [NOIP]2016天天爱跑步

    [NOIP]2016天天爱跑步 标签: LCA 树上差分 NOIP Description 小C同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是 ...

  7. NOIP2016 天天爱跑步 80分暴力

    https://www.luogu.org/problem/show?pid=1600 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养 ...

  8. [NOIp 2016]天天爱跑步

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

  9. 【NOIP2016】【LCA】【树上差分】【史诗级难度】天天爱跑步

    学弟不是说要出丧题吗>>所以我就研究了1天lca又研究了1天tj然后研究了一天天天爱跑步,终于写了出来.(最后的平均用时为240ms...比学弟快了1倍...) 题意:给你颗树,然后有m个 ...

随机推荐

  1. Mysql explain分析sql语句执行效率

    mysql优化–explain分析sql语句执行效率 Explain命令在解决数据库性能上是第一推荐使用命令,大部分的性能问题可以通过此命令来简单的解决,Explain可以用来查看SQL语句的执行效 ...

  2. 一个支持DbFirst、ModelFirst和CodeFirst的数据库小工具DbTool

    DbTool 一个支持DbFirst.ModelFirst和CodeFirst的数据库工具. 简介 这是一个针对 SqlServer 数据库和 C# 开发语言的小工具,可以利用这个小工具生成数据库表对 ...

  3. 设计模式学习——工厂模式(Factory Pattern)

    1.有一个工厂,专门生产不同品牌的汽车.当有人需要从此工厂提货的时候,只需要告诉他,要什么品牌的,就可以了,并不关心这些车是怎么生产出来的. 2.以上方式,如果增加品牌的时候,也要修改工厂,有点麻烦. ...

  4. autofac初识

    在开始autofac时,有必要先了解两个关键词:“控制反转(IoC/Inverse Of Control)”与“依赖注入(DI/Dependence injection)”. 控制反转(IoC):它把 ...

  5. 深入浅出图解【计算机网络】 之 【TCP可靠传输的实现2: 超时重传+拥塞控制】

    [前言]上一篇文章介绍了关于TCP的基础知识,以及建立(释放)连接和滑动窗口的概念. 本篇文章将延续上一篇的思路,继续介绍TCP实现可靠传输的机制. 超时重传 上一篇文章里介绍过TCP采用停止等待协议 ...

  6. CSS 画一个八卦

    效果图: 实现原理: 设置高度为宽度的2倍的一个框,利用 border 补全另一半的宽度,设置圆角 用两个 div 设置不同的颜色,定位到圆的上下指定位置. 最后只剩下里面的小圆圈了.设个宽高,圆角即 ...

  7. react 中使用定时器 Timers(定时器)

    setTimeout,clearTmeout setInterval,clearInterval 在 class 中 class TimersDemo extends Component { cons ...

  8. for循环内嵌套finally使用的意外获得

    在for循环中有continue和break,无论执行continue还是break   finally的逻辑都会执行,原本以为是不执行的 格式 for (int i = 0; i < 3; i ...

  9. ES6-let & const

    let和const命令 let 它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效. for(let i = 0; i < arr.length; i++){} 用let命 ...

  10. asp.net MVC4 框架揭秘 读书笔记系列3

    IIS/ASP.net管道 本节全部用图形表示便于理解和记忆 1.3.1 IIS5.x与asp.net 1.3.2 IIS 6.0与asp.net 1.3.3 IIS7.0与asp.net 基于IIS ...