[NOIP2016]天天爱跑步 题解(树上差分) (码长短跑的快)
Description
Input
Output
输出1行N 个整数,第个整数表示结点的观察员可以观察到多少人。
Sample Input
2 3
1 2
1 4
4 5
4 6
0 2 5 1 2 3
1 5
1 3
2 6
Sample Output
lydrainbowcat讲的真是炒鸡棒啊,这里主要参考他在sfjsjjzn上的讲解
首先,每个玩家跑步的路线可以分成两部分:$S$->$lca(S,T)$ $lca(S,T)$->$T$,后者不包括lca
那么,如果位于节点x的观察员能看到玩家i,当且仅当满足:
1.x在S到lca的路径上,且满足$dep[S_i]-dep[x]=w[x]$
2.x在lca到T的路径上(不含lca),且满足$dep[S_i]+dep[x]-2*dep[lca]=w[x]$
接下来分开计算这两种观察员,最后相加即可
首先看一道题
我们的这道题也可以转化成“路径上投放物品”的问题
以第一种观察员的情况为例
由$dep[S_i]-dep[x]=w[x]$
可得$dep[S_i]=dep[x]+w[x]$
就可以理解为给S到lca的路径上的每个点添加类型为$dep[S_i]$的物品
所求为每个点$w[x]+dep[x]$类型的物品有多少
使用树上差分,将其转化为:
点S处生成物品$dep[S_i]$,点lca处这种物品消失
同理,第二种观察员可以转化为$dep[S_i]-2*dep[lca]$在T生成,在lca消失
所求为$w[x]-dep[x]$的物品数量
权值线段树合并确实是可以的,但本题不需要维护最值,只是求特定数量
所以可以对每个点开vector,把物品的生成和消失记录存在里面
最后统计的时候 开一个数组cnt[]用于统计数量(不是每个点开一个!运用差分的思想!)
递归时先存一下旧的$c[所求]$,回溯的时候用新的值减去它
即为子树和
最后每个点的答案即为两种情况相加
自认为代码可读性还是很高的:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
const int N=;
int n,m,to[N<<],nxt[N<<],head[N],fa[N][],tot=;
int w[N],dep[N],cnt1[N<<],cnt2[N<<],ans1[N],ans2[N];
vector<int> sp[][N],del[][N];
inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>'')
{if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<='')
{x=(x<<)+(x<<)+ch-'';ch=getchar();}
return x*f;
}
void add(int x,int y)
{
to[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
void dfs(int x,int deep)
{
dep[x]=deep;
for(int i=;i<=;i++)
fa[x][i]=fa[fa[x][i-]][i-];
for(int i=head[x];i;i=nxt[i])
{
if(dep[to[i]])continue;
fa[to[i]][]=x;
dfs(to[i],deep+);
}
}
int LCA(int x,int y)
{
if(dep[x]>dep[y])swap(x,y);
for(int i=;i>=;i--)
if(dep[fa[y][i]]>=dep[x])y=fa[y][i];
if(x==y)return x;
for(int i=;i>=;i--)
if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
return fa[x][];
}
void spawn(int pos,int val,int k)
{
sp[k][pos].push_back(val);
}
void remove(int pos,int val,int k)
{
del[k][pos].push_back(val);
}
void cacl1(int x)
{
int now=cnt1[w[x]+dep[x]+n];
for(int i=;i<(int)sp[][x].size();i++)
cnt1[sp[][x][i]]++;
for(int i=;i<(int)del[][x].size();i++)
cnt1[del[][x][i]]--;
for(int i=head[x];i;i=nxt[i])
if(dep[to[i]]>dep[x])cacl1(to[i]);
ans1[x]=cnt1[w[x]+dep[x]+n]-now;
}
void cacl2(int x)
{
int now=cnt2[w[x]-dep[x]+n];
for(int i=;i<(int)sp[][x].size();i++)
cnt2[sp[][x][i]]++;
for(int i=;i<(int)del[][x].size();i++)
cnt2[del[][x][i]]--;
for(int i=head[x];i;i=nxt[i])
if(dep[to[i]]>dep[x])cacl2(to[i]);
ans2[x]=cnt2[w[x]-dep[x]+n]-now;
}
int main()
{
n=read();m=read();
for(int i=;i<n;i++)
{
int x=read(),y=read();
add(x,y);add(y,x);
}
for(int i=;i<=n;i++)
w[i]=read();
dfs(,);
for(int i=;i<=m;i++)
{
int S=read(),T=read(),lca=LCA(S,T);
spawn(S,dep[S]+n,);
remove(fa[lca][],dep[S]+n,);
spawn(T,dep[S]-*dep[lca]+n,);
remove(lca,dep[S]-*dep[lca]+n,);
}
cacl1();
cacl2();
for(int i=;i<=n;i++)
printf("%d ",ans1[i]+ans2[i]);
return ;
}
在自家oj上用时是最慢ac的一半,可以说是性价比极高了?
[NOIP2016]天天爱跑步 题解(树上差分) (码长短跑的快)的更多相关文章
- [luogu1600 noip2016] 天天爱跑步 (树上差分)
题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵 ...
- ☆ [NOIp2016] 天天爱跑步 「树上差分」
题目类型:LCA+思维 传送门:>Here< 题意:给出一棵树,有\(M\)个人在这棵树上跑步.每个人都从自己的起点\(s[i]\)跑到终点\(t[i]\),跑过一条边的时间为1秒.现在每 ...
- bzoj 4719: [Noip2016]天天爱跑步【树上差分+dfs】
长久以来的心理阴影?但是其实非常简单-- 预处理出deep和每组st的lca,在这里我简单粗暴的拿树剖爆算了 然后考虑对于一组s t lca来说,被这组贡献的观察员x当且仅当: x在s到lca的路径上 ...
- NOIP2016 天天爱跑步(树上差分)
题意 给定一棵树,从时刻 0 开始,有若干人从 S[i] 出发向 T[i] 移动,每单位时刻移动一条边 对于树上每个点 x,求 w[x] 时刻有多少人恰好路过 x N,M≤300000 题解 从上午 ...
- NOIP2016天天爱跑步 题解报告【lca+树上统计(桶)】
题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 nn个 ...
- 【NOIP2016】天天爱跑步(树上差分)
题意: 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要 玩家每天按时上线,完成打卡任务.这个游戏的地图可以看作一一棵包含 N个结点 ...
- [NOIP2016]天天爱跑步-题解
题面传送门 解答 设第\(j\)号玩家在\(V_j\)时刻出发. 弱化问题:如果树退化成了一条链.则在\(j\)处的观察员能观察到的\(i\)号玩家当且仅当 \[ i玩家经过j,且 \begin{ca ...
- LOJ2359. 「NOIP2016」天天爱跑步【树上差分】
LINK 思路 首先发现如果对于一个节点,假设一个节点需要统计从字数内来的贡献 需要满足\(dep_u - dep_s = w_u\) 这个条件其实可以转化成\(dep_u - w_u = dep_s ...
- P1600 [NOIP2016 提高组] 天天爱跑步 (树上差分)
对于一条路径,s-t,位于该路径上的观察员能观察到运动员当且仅当以下两种情况成立:(d[ ]表示节点深度) 1.观察员x在s-lca(s,t)上时,满足d[s]=d[x]+w[x]就能观察到,所以我们 ...
随机推荐
- 「NOI2016」网格 解题报告
「NOI2016」网格 容易注意到,答案最多为2,也就是说答案为-\(1,0,1,2\)四种,考虑逐个判断. 无解的情况比较简单 如果\(nm\le c+1\),显然无解 如果\(nm=c+2\),判 ...
- [CSP-S模拟测试]:世界线(DFS+bitset)
题目描述 时间并不是一条单一的线,而是有许多世界线构成的流. 在一些时刻,世界线会发生分裂:同样的,它们也有可能在一些时刻收束在一起.如果将这些时刻抽象成点,那么这些世界线构成的网络,实际上是一张有向 ...
- java动态代理的原理
在许多mvc框架中,经常用到注解来实现面向切面(aop)的编程.面向切面编程,可以对业务逻辑中各部分进行分离,提高程序的重用性,降低各逻辑业务部分的耦合度. jdk中利用反射原理使用Proxy类对对象 ...
- 《ArcGIS Runtime SDK for .NET开发笔记》 --Hello Word
这里我们将创建第一个用于显示地图的APP. 1.新建一个WPF程序 首先我们打开Visual Studio,选择新建项目. 选择已安装——模板——Windows桌面——WPF应用程序 2.添加Run ...
- dotnet core项目的nuget存储路径
Where's the package location in aspnet core For project.json the nuget directory is in the user prof ...
- MySQL高级学习笔记(二):mysql配置文件、mysql的用户与权限管理、mysql的一些杂项配置
文章目录 mysql配置文件 二进制日志log-bin 错误日志log-error 数据文件 两系统 Myisam存放方式 innodb存放方式 如何配置 mysql的用户与权限管理 MySQL的用户 ...
- 运维 04 Shell基础命令(二)
Shell基础命令(二) 查看Linux的发行版 cat /etc/redhat-release cat /etc/os-release 查看系统用户的id信息 id 用户名 id root id ...
- apiDoc部署搭建
apiDoc介绍: 目前,越来越多的项目进行前后端分离,那么就有需要比较规范的来管理API文档.而apiDoc这个API文档管理器,可以根据你项目代码的注释来进行自动生成API文档.同时支持C#.Ja ...
- mysql 针对table的查看命令行
1 desc t_help; 2 show create table t_help; 3 show table status like 't_help';
- python基础之基础数据类型1
int 整形 数字用于计算和比较 python3没有long,python2有整形和长整型 十进制二进制转换方法 bin(10进制) ==二进制 0b(二进制) int("二进制" ...