NOIP2016 天天爱跑步 (树上差分+dfs)
题目大意:给你一颗树,树上每个点都有一个观察员,他们仅会在 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)的更多相关文章
- 洛谷 1600 (NOIp2016) 天天爱跑步——树上差分
题目:https://www.luogu.org/problemnew/show/P1600 看TJ:https://blog.csdn.net/clove_unique/article/detail ...
- [NOIP2016]天天爱跑步(树上差分+线段树合并)
将每个人跑步的路径拆分成x->lca,lca->y两条路径分别考虑: 对于在点i的观察点,这个人(s->t)能被观察到的充要条件为: 1.直向上的路径:w[i]=dep[s]-dep ...
- NOIP2016 天天爱跑步 - 树上差分
传送门 题目分析: 一年前还是个傻子的时候居然直接放弃了这题. 首先列出两个方程:如果i节点的观察员能够观察到由s->t的那个人,那么: \[dep[s] - dep[i] = w[i], de ...
- NOIP2016 Day1 T2 天天爱跑步(树上差分,LCA)
原文链接 原题链接 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏 ...
- 洛谷$P1600$ 天天爱跑步 树上差分
正解:树上差分 解题报告: 传送门$QwQ$! 这题还挺妙的,,,我想了半天才会$kk$ 首先对一条链$S-T$,考虑先将它拆成$S-LCA$和$LCA-T$,分别做.因为总体上来说差不多接下来我就只 ...
- 洛谷P1600 天天爱跑步——树上差分
题目:https://www.luogu.org/problemnew/show/P1600 看博客:https://blog.csdn.net/clove_unique/article/detail ...
- [Noip2016]天天爱跑步 LCA+DFS
[Noip2016]天天爱跑步 Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要玩家每天按时上线,完成打卡任 ...
- [NOIp2016]天天爱跑步 线段树合并
[NOIp2016]天天爱跑步 LG传送门 作为一道被毒瘤出题人们玩坏了的NOIp经典题,我们先不看毒瘤的"动态爱跑步"和"天天爱仙人掌",回归一下本来的味道. ...
- BZOJ 4719--天天爱跑步(LCA&差分)
4719: [Noip2016]天天爱跑步 Time Limit: 40 Sec Memory Limit: 512 MBSubmit: 1464 Solved: 490[Submit][Stat ...
随机推荐
- windows 查看端口号被占用
1.netstat -ano 2.tasklist | findstr xxx 3.进程管理杀掉
- web前端对文件的引用规则
web前端一般常用文件 .html .css .js.但是当用css文件和html引入资源(比如图片)时,路径可能不相同.下面总结了几条. 使用相对路径引入规则: html或者js引入图片,按照htm ...
- Spring 让 LOB 数据操作变得简单易行
概述 LOB 代表大对象数据,包括 BLOB 和 CLOB 两种类型,前者用于存储大块的二进制数据,如图片数据,视频数据等,而后者用于存储长文本数据,如论坛的帖子内容,产品的详细描述等.值得注意的是: ...
- 为屏而生,为屏而死 - IT "精英”们的杯与具
为屏而生,为屏而死 - IT "精英"们的杯与具 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一 ...
- Microsoft Dynamics CRM 2013 for Outlook 的硬件要求
当仅联机或脱机模式下执行 Microsoft Dynamics CRM 2013 for Microsoft Office Outlook 时,下表列出了建议的最低硬件要求 watermark/2/t ...
- 使用android.graphics.Path类自绘制PopupWindow背景
PopupWindow简单介绍 PopupWindow是悬浮在当前activity上的一个容器,用它能够展示随意的内容. PopupWindow跟位置有关的API有以下几个: showAsDropDo ...
- 【Java并发编程实战】—–synchronized
在我们的实际应用其中可能常常会遇到这样一个场景:多个线程读或者.写相同的数据,訪问相同的文件等等.对于这样的情况假设我们不加以控制,是非常easy导致错误的. 在java中,为了解决问题,引入临界区概 ...
- 2015.04.23,外语,读书笔记-《Word Power Made Easy》 12 “如何奉承朋友” SESSION 33
1.eat, drink, and be merry 拉丁动词vivo(to live),加上名词vita(life),是许多重要英文词汇的来源. convivo是拉丁动词to live togeth ...
- 智课雅思词汇---十三、前缀ab-是什么意思
智课雅思词汇---十三.前缀ab-是什么意思 一.总结 一句话总结:分离,脱离;相反;加强意义 前缀:ab- [词根含义]:分离,脱离;相反;加强意义 [词根来源]:来源于拉丁语前缀ab-. [同源单 ...
- Asp.net Web Api中使用配置Unity
第一步:建立web api,添加unity.webapi. 第二步:在添加了该引用之后,在App_Start中会自动生成UnityConfig.cs文件 第三步:添加数据做测试 第四步:展示效果