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 ...
随机推荐
- 【JavaScript框架封装】数据类型检测模块功能封装
数据类型检测封装后的最终模块代码如下: /*数据类型检验*/ xframe.extend(xframe, { // 鸭子类型(duck typing)如果它走起路来像鸭子,叫起来也是鸭子,那么它就是鸭 ...
- UOJ #86 mx的组合数 (数位DP+NTT+原根优化)
题目传送门 matthew99神犇的题解讲得非常清楚明白,跪烂Orzzzzzzzzzzzzz 总结一下,本题有很多重要的突破口 1.Lucas定理 看到n,m特别大但模数特别小时,容易想到$lucas ...
- IP实时传输协议RTP/RTCP详解
1.简介 目前,在IP网络中实现实时语音.视频通信和应用已经成为网络应用的一个主流技术和发展方向,本文详细介绍IP协议族中用于实时语音.视频数据传输的标准协议RTP( Real-time Transp ...
- Django入门--模型系统(二):常用查询及表关系的实现
1.常用查询 模型类上的管理器: ** 模型类.objects ** (1)常用一般查询 rs = Student.objects.all() # 查询所有记录,返回Queryset print(rs ...
- EasyUI闪屏,EasyUI页面加载提示:原理+代码+效果图
使用EasyUI时,有个经常遇到的问题,页面还没有渲染完成的时候,就展现了. 刚刚开始很混乱,等加载完成后,就好了. 参考这篇文章http://blog.csdn.net/zheng0518/arti ...
- C++调用C#编写的DLL【转】
1.打开VS新建项目 2.在新建项目窗口中选择其他语言->Visual C++->Win 32控制台应用程序,设置名称:MathCon,设置解决方案名:MathCon,这个名字随便你自己取 ...
- Git学习总结(4)——我的Git忽略文件
*.bak *.txt *.vm .gitignore #svn .svn/ # built application files *.apk *.ap_ # files for the dex VM ...
- 洛谷——P1802 5倍经验日
https://www.luogu.org/problem/show?pid=1802#sub 题目背景 现在乐斗有活动了!每打一个人可以获得5倍经验!absi2011却无奈的看着那一些比他等级高的好 ...
- 组件的使用(三)AutoCompleteTextView的使用
AutoCompleteTextView经常使用的属性: android:completionHint 下拉列表以下的说明性文字 android:completionThreshold 弹出下来列表的 ...
- NEFU 2
其实就是筛选素数. 如,若能被2是质数,则2的倍数全是合数.如此循环. #include <iostream> #include <math.h> #include <c ...