题意

给定一棵树,从时刻 0 开始,有若干人从 S[i] 出发向 T[i] 移动,每单位时刻移动一条边

对于树上每个点 x,求 w[x]  时刻有多少人恰好路过 x

N,M≤300000

题解

从上午11点做到下午3点45终于做出来了。

一开始坚持自己的想法,发现错了之后不知道怎么改,无奈看了题解。

列出恰好路过的条件并化简
在 Si 到 lca(Si,Ti ) 阶段,应满足 d[Si ]=w[x]+d[x]
在 lca(Si,Ti ) 到 Ti阶段,应满足 d[Si]-2∗d[lca(Si,Ti )]=w[x]-d[x]
相当于在 Si 位置出现一个 A 类数 d[Si ],在 lca(Si,Ti ) 的父节点消失
在 Ti 位置出现一个 B 类数 d[Si ]-2∗d[lca(Si,Ti )],在 lca(Si,Ti ) 消失
求子树 x 中,等于 w[x]+d[x] 的 A 类数个数 + 等于 w[x]-d[x] 的 B 类数个数
全局数组计数,统计遍历子树 x 前后相应位置上的差我一开始就是没注意这死活调不出来
 #include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
const int N=;
vector<int> v1[N],v2[N],v3[N],v4[N];
int cnt,head[N];
int fa[N][],dep[N];
int book1[N],book2[N*];
int n,m,w[N],ans[N];
struct edge{
int to,nxt;
}e[N*];
void add(int u,int v){
cnt++;
e[cnt].nxt=head[u];
e[cnt].to=v;
head[u]=cnt;
}
void dfs1(int u,int f,int deep){
fa[u][]=f;
dep[u]=deep;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(v==f)continue;
dfs1(v,u,deep+);
}
}
int lca(int u,int v){
if(dep[u]<dep[v])swap(u,v);
for(int i=;i>=;i--){
if(dep[fa[u][i]]>=dep[v])u=fa[u][i];
}
if(u==v)return u;
for(int i=;i>=;i--){
if(fa[u][i]!=fa[v][i]){
u=fa[u][i];v=fa[v][i];
}
}
return fa[u][];
}
void dfs2(int u){
ans[u]=book1[w[u]+dep[u]]+book2[w[u]-dep[u]+N];
for(int i=;i<v1[u].size();i++){
book1[v1[u][i]]++;
}
for(int i=;i<v2[u].size();i++){
book1[v2[u][i]]--;
}
for(int i=;i<v3[u].size();i++){
book2[v3[u][i]]++;
}
for(int i=;i<v4[u].size();i++){
book2[v4[u][i]]--;
}
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(v==fa[u][])continue;
dfs2(v);
}
ans[u]=book1[w[u]+dep[u]]+book2[w[u]-dep[u]+N]-ans[u];
}
int main(){
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);
}
dfs1(,,);
for(int i=;i<=;i++)
for(int j=;j<=n;j++)
fa[j][i]=fa[fa[j][i-]][i-];
for(int i=;i<=n;i++){
scanf("%d",&w[i]);
}
for(int i=;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
int c=lca(u,v);
v1[u].push_back(dep[u]);
v2[fa[c][]].push_back(dep[u]);
v3[v].push_back(dep[u]-*dep[c]+N);
v4[c].push_back(dep[u]-*dep[c]+N);
}
for(int i=;i<v1[].size();i++){
book1[v1[][i]]++;
}
for(int i=;i<v2[].size();i++){
book1[v2[][i]]--;
}
for(int i=;i<v3[].size();i++){
book2[v3[][i]]++;
}
for(int i=;i<v4[].size();i++){
book2[v4[][i]]--;
}
dfs2();
for(int i=;i<=n;i++){
printf("%d ",ans[i]);
}
return ;
}

NOIP2016 天天爱跑步(树上差分)的更多相关文章

  1. 洛谷 1600 (NOIp2016) 天天爱跑步——树上差分

    题目:https://www.luogu.org/problemnew/show/P1600 看TJ:https://blog.csdn.net/clove_unique/article/detail ...

  2. NOIP2016 天天爱跑步 (树上差分+dfs)

    题目大意:给你一颗树,树上每个点都有一个观察员,他们仅会在 w[i] 时刻出现,观察正在跑步的玩家 一共有m个玩家,他们分别从节点 s[i] 同时出发,以每秒跑一条边的速度,沿着到 t[i] 的唯一路 ...

  3. [NOIP2016]天天爱跑步(树上差分+线段树合并)

    将每个人跑步的路径拆分成x->lca,lca->y两条路径分别考虑: 对于在点i的观察点,这个人(s->t)能被观察到的充要条件为: 1.直向上的路径:w[i]=dep[s]-dep ...

  4. NOIP2016 天天爱跑步 - 树上差分

    传送门 题目分析: 一年前还是个傻子的时候居然直接放弃了这题. 首先列出两个方程:如果i节点的观察员能够观察到由s->t的那个人,那么: \[dep[s] - dep[i] = w[i], de ...

  5. NOIP2016 Day1 T2 天天爱跑步(树上差分,LCA)

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

  6. 洛谷P1600 天天爱跑步——树上差分

    题目:https://www.luogu.org/problemnew/show/P1600 看博客:https://blog.csdn.net/clove_unique/article/detail ...

  7. 洛谷$P1600$ 天天爱跑步 树上差分

    正解:树上差分 解题报告: 传送门$QwQ$! 这题还挺妙的,,,我想了半天才会$kk$ 首先对一条链$S-T$,考虑先将它拆成$S-LCA$和$LCA-T$,分别做.因为总体上来说差不多接下来我就只 ...

  8. BZOJ 4719--天天爱跑步(LCA&差分)

    4719: [Noip2016]天天爱跑步 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 1464  Solved: 490[Submit][Stat ...

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

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

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

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

随机推荐

  1. JavaScript学习记录二

    title: JavaScript学习记录二 toc: true date: 2018-09-13 10:14:53 --<JavaScript高级程序设计(第2版)>学习笔记 要多查阅M ...

  2. Codeforces 659F Polycarp and Hay 并查集

    链接 Codeforces 659F Polycarp and Hay 题意 一个矩阵,减小一些数字的大小使得构成一个连通块的和恰好等于k,要求连通块中至少保持一个不变 思路 将数值从小到大排序,按顺 ...

  3. 移动端 input光标问题 以及 监听输入

    1.  input 框光标问题: input框 在ios上显示的与Android是不一样的 显示是这样的 而且在输入的时候 光标位置变化了 是这样的 为了达到一致的效果 在行高加上\9     如:l ...

  4. Codeforces 986B. Petr and Permutations(没想到这道2250分的题这么简单,早知道就先做了)

    这题真的只能靠直觉了,我没法给出详细证明. 解题思路: 1.交换3n次或者7n+1次,一定会出现一个为奇数,另一个为偶数. 2.用最朴素的方法,将n个数字归位,计算交换次数. 3.判断交换次数是否与3 ...

  5. js 关于height()、innerHeight()、outerHeight()函数的区别

  6. [APIO2012]派遣 可并堆(左偏树)

    没啥说的,自底向上合并大根堆即可. 一边合并,一边贪心弹堆顶直到堆的总和不大于预算. Code: #include <cstdio> #include <algorithm> ...

  7. KVM 日常使用命令

    [root@Eren liwm]# ps ax | grep kvm  681 ?        S<     0:00 [kvm-irqfd-clean]17597 pts/0    S+   ...

  8. python学习笔记:第四天

    day04: 一.计算求值 num += 1 等价于 num = num + 1num -= 1 等价于 num = num - 1num *= 2 等价于 num = num * 2num /= 2 ...

  9. ztree实现根节点单击事件,显示节点信息

    这段时间在维护公司的项目,去年做的项目里面有ztree树的例子,想起之前还没有开始写博客,一些知识点也无从找起,要新加一个右击节点事件,折腾了半天,其中也包含了一些知识点,稍稍做了一些demo. zT ...

  10. asp.net C# 获取网页源代码的几种方式

    1 方法 System.Net.WebClient aWebClient = new System.Net.WebClient(); aWebClient.Encoding = System.Text ...