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 ...
随机推荐
- 封装自己的jquery框架
jQuery is a fast small JavaScript library 如何封装自己的jQuery <script> // 这里使用沙箱模式,可以防止全局污染 (functio ...
- 再见,OI(2019退役祭)
有些话应该藏在心里,有些事情只属于自己. (想了一下,自己的OI生涯.自己所经历的事情还是留在自己的心里吧,一是自己文笔不好,二是每个人的世界观不同对事情的看法不同) 不要轻易地去评价一个人,每个人背 ...
- [luogu2047 NOI2007] 社交网络 (floyed最短路)
传送门 输入输出样例 输入样例#1: 4 4 1 2 1 2 3 1 3 4 1 4 1 1 输出样例#1: 1.000 1.000 1.000 1.000 题解 在进行floyed的过程中,顺便更新 ...
- PHP学习总结(6)——PHP入门篇之PHP语句结束符
PHP语句结束符 有的小伙伴们是不是已经注意在每一条PHP代码行结尾处都会有一个分号:.对的,这点注意,在PHP编程中需要在每条语句的末尾加入分号:.但要注意,分号:一定在半角状态下输入噢.
- 公司组织oracle培训的理解
oracle执行机制 1.客户端发送一条sql给oracle服务器,oracle会看这条sql的执行计划是否存在缓存 如果存在则直接运行,如果不存在执行第二步. 2.如果不存在缓存 则会 进行语法检 ...
- ZOJ 3203
很简单的一题,注意墙上的影子是放大就行.用三分. #include <iostream> #include <cstdio> #include <cstring> ...
- POI进行ExcelSheet的拷贝
POI进行ExcelSheet的拷贝 学习了:http://www.360doc.com/content/17/0508/20/42823223_652205632.shtml,这个也需要改改 这个: ...
- UVa 170 - Clock Patience
题目:Clock Patience游戏,将52张扑克牌,按时钟依次分成13组(中心一组),每组4张全都背面向上, 从中间组最上面一张牌開始.翻过来设为当前值,然后取当前值相应组中最上面的背过去的牌翻过 ...
- @Autowired 凝视遇到的问题,@Qualifier 帮助解决这个问题
当候选 Bean 数目不为 1 时的应对方法 在默认情况下使用 @Autowired 凝视进行自己主动注入时,Spring 容器中匹配的候选 Bean 数目必须有且仅有一个. 当找不到一个匹配的 Be ...
- 【VC编程技巧】窗口☞3.5对单文档或者多文档程序制作启动画面
(一)概要: 文章描写叙述了如何通过Visual C++ 2012或者Visual C++ .NET,为单文档或者多文档程序制作启动画面.在Microsoft Visual Studio 6.0中对于 ...