[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]就能观察到,所以我们 ...
随机推荐
- webpack 兼容低版本浏览器,转换ES6 ES7语法
ES6,ES7真的太棒了,async +await+Promise,让我阅读代码的时候不用再从左拉到右了(异步太多,一层套一层真的太头痛) 但是有个问题,打包后低版本浏览器运行不了,还有我用了一些混淆 ...
- Echarts 甘特图教程
Echarts甘特图教程 echarts官网实例: https://gallery.echartsjs.com/editor.html?c=xEYpsVs30s 效果: 代码: <html& ...
- 数组转xls格式的excel文件&数据转csv格式的excle
/** * 数组转xls格式的excel文件 * @param array $data 需要生成excel文件的数组 * @param string $filename 生成的excel文件名 * 示 ...
- $router和router区别
this.$router.push({path:'/'})//这个是js编程式的一种动态跳转路由方式,是全局的路由对象. 而写在router声明文件中的router是自己定义实例化的一个对象.可以使用 ...
- Python面向对象 杂篇(后记)
异常处理 什么是异常: 我们在调试程序时,常常会因为各种报错信息导致程序无法运行,异常也是一个对象,用来表示错误.我们可以捕捉异常,并做相应处理,从而增加代码的友好程度. 异常处理: ...
- ZROI week4
考试 前言 起晚了,大概10点才开始看T1,被别人问了T2有点懵逼. 和 这题看了就A掉了,感觉很像原题的样子,是我的错觉吗?? 串串 某神仙有个\(O(n)\)做法问了我一下,我当时也没怎么想(因为 ...
- 提供 web前端、H5、html页面 技术服务
如有前端页面的需求请在评论区留言 第一时间进行回复
- linux(centos6) 常用操作
目录 一.开机关机 1.Linux centos重启命令: 2.Linux centos关机命令: 二.图形界面与命令界面的切换 1.修改/etc/inittab文件,文件中,最后一行id:5:ini ...
- Java第四次作业,面向对象高级特性(继承和多态)
Java第四次作业-面向对象高级特性(继承和多态) (一)学习总结 1.学习使用思维导图对Java面向对象编程的知识点(封装.继承和多态)进行总结. 2.阅读下面程序,分析是否能编译通过?如果不能,说 ...
- Linux命令 who
who :显示当前登入系统的用户信息 显示的内容主要包括: 用户名,登录终端,上线时间,停留时间,动作,UID等 权限:所有使用者 语法: who [option] ...[ file | arg1 ...