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就不会了于是怀疑人生良久... 啊好像很多大爷都是用线段树合并写的,我怎么什么数据结构都不会啊呜呜呜... 题目大意就 ...
随机推荐
- Python运维开发基础04-语法基础
上节作业回顾(讲解+温习90分钟) #!/usr/bin/env python3 # -*- coding:utf-8 -*- # author:Mr.chen # 仅用列表+循环实现"简单 ...
- gpg的使用
[gpg的使用] 在Linux系统中,gpg程序可以实现非对称加密. 下面简单介绍gpg命令的用法:一.创建密钥:$ gpg --gen-key Please select what kind of ...
- ubuntu12.04安装nox-classic
Setup Nox repo for ânox-dependenciesâ package $ cd /etc/apt/sources.list.d/ $ wget http://openfl ...
- event.preventDefault() vs. return false
使用jquery方式的话,以下是等效的 return false === event.stopPropagation + event.preventDefault() //1. event.preve ...
- 同时安装2个版本的python
使用pip 当Python2和Python3同时存在于windows上时,它们对应的pip都叫pip.exe,所以不能够直接使用 pip install 命令来安装软件包.而是要使用启动器py.exe ...
- mysql 更新替换字符串
update zxg set newlevel = REPLACE(newlevel,'b','') 把表zxg中的newlevel字段中的b删除
- postman的使用方法详解!最全面的教程
文章来源:http://www.cnplugins.com/tool/specify-postman-methods.html 一 简介 Postman 是一款功能超级强大的用于发送 HT ...
- 【PAT】1063. Set Similarity (25) 待改进
Given two sets of integers, the similarity of the sets is defined to be Nc/Nt*100%, where Nc is the ...
- 结对项目— 词频统计2(语言C++)
结对对象:季天梦 博客地址:http://www.cnblogs.com/jitianmeng/ github链接:https://github.com/liuyutianlyt/EX_4.md 比例 ...
- 如何为SharePoint文档库、文件夹、文件单独设置权限
在这里使用截图的方式简单描述两个问题:设置SharePoint Server文档库权限和文档库中的文件夹权限 一.设置SharePoint Server文档库权限 Figure 1 - 打开文档库后, ...