题目大意:给你一颗树,树上每个点都有一个观察员,他们仅会在 w[i] 时刻出现,观察正在跑步的玩家

一共有m个玩家,他们分别从节点 s[i] 同时出发,以每秒跑一条边的速度,沿着到 t[i] 的唯一路径向节点t[i]奔跑

如果一名玩家已经到达了终点,那么在他到达终点之后出现在终点的观察员不会观察到他

但如果在到达终点的同时观察员也出现在终点,那么观察员可以观察到他

求每个节点的观察员观察到玩家的数量

对于每个玩家的奔跑路线,可以拆成两部分

<1>向上跑,从 u 向 lca 奔跑

显然,玩家 u 能对观察员 i 产生1点贡献的充要条件为

显然,向上走的路线能对 i 点产生共贡献的条件是,起点 u 在 i 的子树中

我们只需要统计符合条件的即可

<2>向下跑,从 lca 向 v 奔跑

那么显然

推导可得

显然,向下走的路线能对i点产生共贡献的条件是,终点 v 在 i 的子树中

类似于上面的方法,我们只需要统计符合条件的即可

我们可以用vector在u,v,lca这三个点上打差分,存符合条件的值,注意值可能为负数

而其他子树的结果会影响答案,所以深搜统计一次答案,再用回溯的答案减去深搜的答案即可

方法比较奇葩大家凑合看吧。。。

 #include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#define N 300010
#define maxn 300000
using namespace std; int n,m,cte;
int dep[N],fa[N],tp[N],sz[N],son[N],ans[N];
int w[N],s[N],t[N],F[N],bac[N*],head[N],tmp[N];
struct EDGE{
int to,nxt;
}edge[N*];
vector<int>S[N];
vector<int>E[N];
int gc()
{
int rett=,fh=;char p=getchar();
while(p<''||p>'') {if(p=='-')fh=-;p=getchar();}
while(p>=''&&p<='') {rett=rett*+p-'';p=getchar();}
return rett*fh;
}
void edge_add(int u,int v)
{
cte++;
edge[cte].to = v;
edge[cte].nxt=head[u];
head[u]=cte;
}
void Tsp1(int u,int dad)
{
for(int j=head[u];j!=-;j=edge[j].nxt)
{
int v=edge[j].to;
if(v==dad) continue;
dep[v]=dep[u]+;
fa[v]=u;
Tsp1(v,u);
if(sz[v]>sz[son[u]]) son[u]=v;
sz[u]+=sz[v];
}
sz[u]++;
}
void Tsp2(int u)
{
if(son[u]) tp[son[u]]=tp[u],Tsp2(son[u]);
for(int j=head[u];j!=-;j=edge[j].nxt)
{
int v=edge[j].to;
if(v==fa[u]||v==son[u]) continue;
tp[v]=v;
Tsp2(v);
}
}
int LCA(int x,int y)
{
while(tp[x]!=tp[y])
{
if(dep[tp[x]]<dep[tp[y]]) swap(x,y);
x=fa[tp[x]];
}
return dep[x]<=dep[y]?x:y;
}
void dfs1(int u)
{
tmp[u]=bac[dep[u]+w[u]+maxn];
for(int j=head[u];j!=-;j=edge[j].nxt)
{
int v=edge[j].to;
if(v==fa[u]) continue;
dfs1(v);
}
for(int i=;i<S[u].size();i++)
bac[S[u][i]+maxn]++;
ans[u]+=bac[dep[u]+w[u]+maxn]-tmp[u];
for(int i=;i<E[u].size();i++)
bac[E[u][i]+maxn]--;
}
void dfs2(int u)
{
tmp[u]=bac[w[u]-dep[u]+maxn];
for(int j=head[u];j!=-;j=edge[j].nxt)
{
int v=edge[j].to;
if(v==fa[u]) continue;
dfs2(v);
}
for(int i=;i<E[u].size();i++)
bac[E[u][i]+maxn]--;
for(int i=;i<S[u].size();i++)
bac[S[u][i]+maxn]++;
ans[u]+=bac[w[u]-dep[u]+maxn]-tmp[u];
} int main()
{
freopen("running1.in","r",stdin);
//freopen("running6.out","w",stdout);
scanf("%d%d",&n,&m);
int x,y;
memset(head,-,sizeof(head));
for(int i=;i<n;i++)
{
x=gc(),y=gc();
edge_add(x,y);
edge_add(y,x);
}
tp[]=;
Tsp1(,-);
Tsp2();
for(int i=;i<=n;i++) w[i]=gc();
for(int i=;i<=m;i++)
{
s[i]=gc(),t[i]=gc();
F[i]=LCA(s[i],t[i]);
S[s[i]].push_back(dep[s[i]]);
E[F[i]].push_back(dep[s[i]]);
}
//debug();
dfs1();
for(int i=;i<=n;i++)
{
S[i].clear(),E[i].clear();
}
memset(tmp,,sizeof(tmp));
for(int i=;i<=m;i++)
{
S[t[i]].push_back(dep[s[i]]-*dep[F[i]]);
E[F[i]].push_back(dep[s[i]]-*dep[F[i]]);
}
dfs2();
for(int i=;i<=n;i++) printf("%d ",ans[i]);
return ;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. PHP 使用 Kafka 安装拾遗

    最近项目开发中需要使用 Kafka 消息队列.经过检索,PHP下面有通用的两种方式来调用 Kafka . php-rdkafka 扩展 以 PHP 扩展的形式进行使用是非常高效的.另外,该项目也提供了 ...

  2. 【hihocoder 1304】搜索一·24点

    [题目链接]:http://hihocoder.com/problemset/problem/1304 [题意] [题解] 按照题目给的方法搜索就好; 那个方法很棒啊. 注意除0; 然后是浮点数的比较 ...

  3. 【POJ】3122 Pie [二分查找]

    题目地址:http://poj.org/problem?id=3122 二分每块饼的体积.为了保证精度,可以先二分半径的平方r*r,最后再乘以PI.要注意一点,要分的人数要包括自己,及f+1. #in ...

  4. BA-防冻开关的安装

    防冻开关学名:防冻恒温保护器,在通风空调系统中监测加热盘管空气侧温度来防止盘管冻坏.具有较小的转换差和良好的重复性.可自动复位.当在30cm长的毛细管上温度低于选择的设定值时会产生一个闭合信号给DDC ...

  5. [ACM] POJ 2154 Color (Polya计数优化,欧拉函数)

    Color Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 7630   Accepted: 2507 Description ...

  6. JMX学习笔记(一)-MBean

    JMX学习笔记(一)-MBean 标签: jmxstringjavainterfaceexceptionclass 2010-12-07 22:20 15360人阅读 评论(5) 收藏 举报  分类: ...

  7. ELF文件格式定义

    ELF(Executable and Linking Format)是一种对象文件的格式,用于定义不同类型的对象文件(Object files)中都放了什么东西.以及都以什么样的格式去放这些东西.它自 ...

  8. ROS-单目摄像头标定

    前言:由于摄像图内部与外部的原因,生成的图像往往会发生畸变,为了避免数据源造成的误差,需要针对摄像头的参数进行标定. ros官方提供了camera_calibration软件包进行摄像头标定. 一.安 ...

  9. kettle的下载、安装和初步使用(Ubuntu 16.04平台下)(图文详解)

    不多说,直接上干货! 能够看我这篇博客的博友们,想必是已经具备一定基础了. 扩展博客 kettle的下载.安装和初步使用(windows平台下)(图文详解) kettle的下载 žKettle可以在h ...

  10. ubuntu16.04 安装 docker-compose

    下载安装 docker-composecurl -L https://github.com/docker/compose/releases/download/1.15.0/docker-compose ...