BZOJ 4719--天天爱跑步(LCA&差分)
4719: [Noip2016]天天爱跑步
Time Limit: 40 Sec Memory Limit: 512 MB
Submit: 1464 Solved: 490
[Submit][Status][Discuss]
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
HINT
题目链接:
http://www.lydsy.com/JudgeOnline/problem.php?id=4719
Solution
刚开始学OI的时候就看过这道题。。。当时是贴代码过的。。。。
记得好像是用树链剖分。。不记得了。。反正很长。。。
现在快要noip了。。。把往年的题目拿出来看一下,算是临近noip的梳理吧。。。。。
好多废话
进入正题。。。。。
首先每个人都要走最短路径。。。马上想到LCA。。。不然还能有什么。。。
每个人分别统计显然是不行的,不过似乎可以根据特殊情况水很多分。。
于是想到差分。。
假设第 i 个人的起点为 Si ,终点为 Ti 。。LCA ( Si ,Ti ) = rt
每条线段长度都是 1 ,故路径长度与深度有关。。。
于是路径就可以分成两部分:Si -> rt 和 rt ->Ti
两条路径分开统计。。。
在向上的路径中,比如一个起点 Si ,深度为 dep [ Si ] ,
那么可以在遍历到Si的时候 U [ dep [ Si ] ] ++;
然后在到达 rt 的父亲的时候 U [ dep [ Si ] ] --; (U [ i ]表示某一方向路径的总值)
向下的路径用一样的方法。。。但这样rt 的统计会有重复。。
所以两次统计中要有一次在 rt 的时候就 U [ dep [ Si ] ] - - ;
这样就可以了,虽然分析很长但代码不是很长。。。。
注意在BZOJ上提交不能有末尾空格。。。害我PE了一发。。。
代码
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#define N 400000
using namespace std;
inline int Read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,m,cnt=0;
int fa[N][22];
int hed[N],w[N],dep[N],ans[N],U[N],D[N<<1];
struct edge{
int r,nxt;
}e[N<<1];
struct node{
int u,w;
};
vectore1[N],e2[N<<1];
void insert(int u,int v){
e[++cnt]=(edge){v,hed[u]};hed[u]=cnt;
e[++cnt]=(edge){u,hed[v]};hed[v]=cnt;
}
void dfs1(int x,int F){
for(int i=1;(1<<i)<=dep[x];i++)
fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=hed[x];i;i=e[i].nxt)
if(e[i].r!=F){
dep[e[i].r]=dep[x]+1;
fa[e[i].r][0]=x;
dfs1(e[i].r,x);
}
}
int lca(int u,int v){
if(dep[u]<dep[v])swap(u,v);
int d=dep[u]-dep[v];
for(int i=0;(1<<i)<=d;i++)
if((1<<i)&d)
u=fa[u][i];
if(u==v)return u;
for(int i=20;i>=0;i--){
if((1<<i)>dep[u] || fa[u][i]==fa[v][i])continue;
u=fa[u][i];v=fa[v][i];
}
return fa[u][0];
}
void dfs2(int x,int F){
ans[x]-=U[w[x]+dep[x]];
ans[x]-=D[w[x]-dep[x]+n];
for(int i=0;i<e1[x].size();i++)
U[e1[x][i].u]+=e1[x][i].w;
for(int i=0;i<e2[x].size();i++)
D[e2[x][i].u+n]+=e2[x][i].w;
for(int i=hed[x];i;i=e[i].nxt)
if(e[i].r!=F)
dfs2(e[i].r,x);
ans[x]+=U[w[x]+dep[x]]+D[w[x]-dep[x]+n];
}
int main(){
int u,v,rt;
n=Read();m=Read();
for(int i=1;i<n;i++){
u=Read();v=Read();
insert(u,v);
}
for(int i=1;i<=n;i++)
w[i]=Read();
dfs1(1,0);
for(int i=1;i<=m;i++){
u=Read();v=Read();
rt=lca(u,v);
e1[u].push_back((node){dep[u],1});
e1[rt].push_back((node){dep[u],-1});
e2[v].push_back((node){dep[u]-(dep[rt]<<1),1});
e2[fa[rt][0]].push_back((node){dep[u]-(dep[rt]<<1),-1});
}
dfs2(1,0);
for(int i=1;i<n;i++)
printf("%d ",ans[i]);
printf("%d",ans[n]);
return 0;
}
This passage is made by Iscream-2001.
BZOJ 4719--天天爱跑步(LCA&差分)的更多相关文章
- [NOIP 2016D2T2/Luogu P1600] 天天爱跑步 (LCA+差分)
待填坑 Code //Luogu P1600 天天爱跑步 //Apr,4th,2018 //树上差分+LCA #include<iostream> #include<cstdio&g ...
- [BZOJ 4719] 天天爱跑步
Link: BZOJ 4719 传送门 Solution: 感觉求LCA又有了新姿势啊:$Tarjan$离线$O(n+m)$ 每次递归返回时将子树和父节点合并,如果询问节点已访问过则LCA就是已合并的 ...
- NOIP2016 Day1 T2 天天爱跑步(树上差分,LCA)
原文链接 原题链接 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏 ...
- UOJ261 【NOIP2016】天天爱跑步 LCA+动态开点线段树
UOJ261 [NOIP2016]天天爱跑步 Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.天天爱跑步是一个养成类游戏,需要玩家每天按时上线, ...
- [Noip2016]天天爱跑步 LCA+DFS
[Noip2016]天天爱跑步 Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要玩家每天按时上线,完成打卡任 ...
- [luogu]P1600 天天爱跑步[LCA]
[luogu]P1600 [NOIP 2016]天天爱跑步 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上 ...
- [NOIP2016]天天爱跑步(树上差分+线段树合并)
将每个人跑步的路径拆分成x->lca,lca->y两条路径分别考虑: 对于在点i的观察点,这个人(s->t)能被观察到的充要条件为: 1.直向上的路径:w[i]=dep[s]-dep ...
- NOIP2016 天天爱跑步 (树上差分+dfs)
题目大意:给你一颗树,树上每个点都有一个观察员,他们仅会在 w[i] 时刻出现,观察正在跑步的玩家 一共有m个玩家,他们分别从节点 s[i] 同时出发,以每秒跑一条边的速度,沿着到 t[i] 的唯一路 ...
- NOIP2016Day1T2天天爱跑步(LCA+桶)
据说是今年NOIP最难一题了...我还记得当时满怀期待心情点开Day1的题发现T2就不会了于是怀疑人生良久... 啊好像很多大爷都是用线段树合并写的,我怎么什么数据结构都不会啊呜呜呜... 题目大意就 ...
随机推荐
- centos7.3 防火墙设置
1.查看firewall服务状态 systemctl status firewalld 2.查看firewall的状态 firewall-cmd --state 3.开启.重启.关闭.firewall ...
- SQL Server判断数据库、表、存储过程、函数是否存在
--判断数据库是否存在 if exists (select * from sys.databases where name = '数据库名') drop database [数据库名] --判断表是否 ...
- 单源最短路:Dijkstra算法 及 关于负权的讨论
描述: 对于图(有向无向都适用),求某一点到其他任一点的最短路径(不能有负权边). 操作: 1. 初始化: 一个节点大小的数组dist[n] 源点的距离初始化为0,与源点直接相连的初始化为其权重,其他 ...
- spring框架 构造方法注入
在resources里面新建applicationContext.xml 配置如下: <?xml version="1.0" encoding="UTF-8&quo ...
- send anywhere真的好用啊
手机和电脑互传文件,方便很多.
- CSGL
glShadeModel void glShadeModel(GLenum mode) GL_FLAT/[GL_SMOOTH] 着色技术选择 glClearDepth GL.glClearDepth( ...
- ubuntu的命令行状态和图形化界面切换 (转)
1.ubuntu命令状态切换到图形化界面 startx 如果命令不能识别 执行 sudo apt-get install xinit 还需要提前安装桌面环境 比如 gnome 比如 KDE 安装方法 ...
- 使用delphi 开发多层应用(二十一)使用XE5 RESTClient 直接访问kbmmw 数据库
delphi XE5 出来了,增加了android 的开发支持,另外增加了一个RESTClient 来支持访问REST 服务器. 这个功能非常强大,可以直接使用非常多的REST 服务器.同时也可以支持 ...
- JQuery和JS操作LocalStorage/SessionStorage的方法(转)
出处:http://blog.csdn.net/djzhao627/article/details/50747628 首先说一下LocalStorage和SessionStorage LocalSto ...
- LinUX系统ThinkPHP5链接MsSQL数据库的pdo_dblib扩展
LinUX(centOS6.8)系统ThinkPHP5链接MsSQL数据库的pdo_dblib扩展第一步 下载并安装freetds-current.tar.gz下载地址如下ftp://ftp.free ...