[Noip2016]天天爱跑步 LCA+DFS
[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
HINT
题解:一年前多的题了,不过现在再做的话已经不是那个难度了。
想法有点古怪,直接上做法吧:
对于玩家a->b,设a,b的lca是c,路径长度是len,那么路径可以拆成2半,如果观察员i想看到第一半,那么要求dep[a]-dep[i]=w[i]->dep[a]=dep[i]+w[i],且i是a的祖先;如果i想看到第二半,那么要求len-(dep[b]-dep[i])=w[i]->len-dep[b]=w[i]-dep[i],且i是b的祖先。当然,还有一个要求,就是i在c的子树中,但是我们先不考虑这个。那么做法如下:
在DFS访问到x时,先记录之前有多少点的dep[a]=dep[x]+w[x]以及len-dep[b]=w[x]-dep[x](用桶即可),记为ans1,然后遍历x的子树,遍历结束后,将x位置的玩家的dep[a]以及len-dep[b]加入到桶中,再查询此时有多少点的dep[a]=dep[x]+w[x]以及len-dep[b]=w[x]-dep[x],记为ans2,那么ans2-ans1就是x的答案。
但是如果考虑到i在c的子树中这个条件呢?也好办,只需要在c和c的父亲中加入dep[a]和len-dep[b],并且权值都是-1即可。
如果用tarjan求LCA,则时间复杂度是O(n)的,但是我懒啊~
#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
using namespace std;
const int maxn=300010;
vector<int> v1[maxn],v2[maxn];
int n,m,cnt;
int head[maxn],to[maxn<<1],next[maxn<<1],w[maxn],dep[maxn],Log[maxn],fa[20][maxn];
int s1[maxn],s2[maxn<<1],ans[maxn];
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
void dfs1(int x)
{
for(int i=head[x];i!=-1;i=next[i]) if(to[i]!=fa[0][x])
fa[0][to[i]]=x,dep[to[i]]=dep[x]+1,dfs1(to[i]);
}
inline int lca(int a,int b)
{
if(dep[a]<dep[b]) swap(a,b);
int i;
for(i=Log[dep[a]-dep[b]];i>=0;i--) if(dep[fa[i][a]]>=dep[b]) a=fa[i][a];
if(a==b) return a;
for(i=Log[dep[a]];i>=0;i--) if(fa[i][a]!=fa[i][b]) a=fa[i][a],b=fa[i][b];
return fa[0][a];
}
void dfs2(int x)
{
int i;
ans[x]-=s1[dep[x]+w[x]]+s2[w[x]-dep[x]+n];
for(i=head[x];i!=-1;i=next[i]) if(to[i]!=fa[0][x]) dfs2(to[i]);
for(i=0;i<(int)v1[x].size();i++)
{
if(v1[x][i]>0) s1[v1[x][i]]++;
else s1[-v1[x][i]]--;
}
for(i=0;i<(int)v2[x].size();i++)
{
if(v2[x][i]>0) s2[v2[x][i]]++;
else s2[-v2[x][i]]--;
}
ans[x]+=s1[dep[x]+w[x]]+s2[w[x]-dep[x]+n];
}
inline void add(int a,int b)
{
to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
}
int main()
{
n=rd(),m=rd();
int i,j,a,b,c,d;
memset(head,-1,sizeof(head));
for(i=1;i<n;i++) a=rd(),b=rd(),add(a,b),add(b,a);
for(i=1;i<=n;i++) w[i]=rd();
dep[1]=1,dfs1(1);
for(i=2;i<=n;i++) Log[i]=Log[i>>1]+1;
for(j=1;(1<<j)<=n;j++) for(i=1;i<=n;i++) fa[j][i]=fa[j-1][fa[j-1][i]];
for(i=1;i<=m;i++)
{
a=rd(),b=rd(),c=lca(a,b),d=dep[a]+dep[b]-2*dep[c];
v1[a].push_back(dep[a]),v1[fa[0][c]].push_back(-dep[a]);
v2[b].push_back(d-dep[b]+n),v2[c].push_back(-(d-dep[b]+n));
}
dfs2(1);
for(i=1;i<n;i++) printf("%d ",ans[i]);
printf("%d",ans[n]);
return 0;
}
[Noip2016]天天爱跑步 LCA+DFS的更多相关文章
- [NOIP2016] 天天爱跑步 桶 + DFS
---题面--- 题解: 很久以前就想写了,一直没敢做,,,不过今天写完没怎么调就过了还是很开心的. 首先我们观察到跑步的人数是很多的,要一条一条的遍历显然是无法承受的,因此我们要考虑更加优美的方法. ...
- luogu1600 [NOIp2016]天天爱跑步 (tarjanLca+dfs)
经过部分分的提示,我们可以把一条路径切成s到lca 和lca到t的链 这样就分为向上的链和向下的链,我们分开考虑: 向上:如果某一个链i可以对点x产生贡献,那么有deep[x]+w[x]=deep[S ...
- [NOIp2016]天天爱跑步 线段树合并
[NOIp2016]天天爱跑步 LG传送门 作为一道被毒瘤出题人们玩坏了的NOIp经典题,我们先不看毒瘤的"动态爱跑步"和"天天爱仙人掌",回归一下本来的味道. ...
- 【LG1600】[NOIP2016]天天爱跑步
[LG1600][NOIP2016]天天爱跑步 题面 洛谷 题解 考虑一条路径\(S\rightarrow T\)是如何给一个观测点\(x\)造成贡献的, 一种是从\(x\)的子树内出来,另外一种是从 ...
- BZOJ 4719--天天爱跑步(LCA&差分)
4719: [Noip2016]天天爱跑步 Time Limit: 40 Sec Memory Limit: 512 MBSubmit: 1464 Solved: 490[Submit][Stat ...
- NOIP2016天天爱跑步 题解报告【lca+树上统计(桶)】
题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 nn个 ...
- UOJ261 【NOIP2016】天天爱跑步 LCA+动态开点线段树
UOJ261 [NOIP2016]天天爱跑步 Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.天天爱跑步是一个养成类游戏,需要玩家每天按时上线, ...
- [luogu]P1600 天天爱跑步[LCA]
[luogu]P1600 [NOIP 2016]天天爱跑步 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上 ...
- BZOJ4719 [Noip2016]天天爱跑步
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转 ...
随机推荐
- Intellij IDEA 2017 破解
http://idea.lanyus.com/ https://www.cnblogs.com/wang1024/p/7485758.html
- 爪哇国新游记之十九----使用Stack检查数字表达式中括号的匹配性
/** * 辅助类 * 用于记载字符和位置 * */ class CharPos{ char c; int pos; public CharPos(char c,int pos){ this.c=c; ...
- <LeetCode OJ> 328. Odd Even Linked List
328. Odd Even Linked List Total Accepted: 9271 Total Submissions: 24497 Difficulty: Easy Given a sin ...
- Java 通过JDBC连接Mysql数据库的方法和实例
JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口 ...
- html5表单验证(Bootstrap)
html5表单验证(Bootstrap) 邮箱验证: <input name="email" type="text" placeholder=&quo ...
- libevent2源码分析之三:信号的初始化流程
libevent2对信号的响应也进行了封装,使之与socket操作一样对外提供统一的接口.这里的信号一般指linux的信号.由于信号与socket相关的编程接口有较大的不同,因此在内部实现也有一些区别 ...
- C++中string.find()函数与string::npos
先说说string::npos参数: npos 是一个常数,用来表示不存在的位置,类型一般是std::container_type::size_type 许多容器都提供这个东西.取值由实现决定,一般是 ...
- Swift 泛型參数
原文:http://www.cocoachina.com/newbie/basic/2014/0612/8802.html 本页内容包含:泛型形參语句和泛型实參语句 本节涉及泛型类型.泛型函数以及泛型 ...
- 把.apk传到站点server下载
刚刚解决的一个问题,做好的apk上传到server,通过訪问链接下载apk. 解决方法:设置IIS的MIME类型,让IIS web下载支持包含APK等文件在内的多文件类型 1.打开IIS站点,右键属性 ...
- Python进程、线程、协程之间的关系
一.从操作系统角度 操作系统处理任务, 调度单位是 进程 和 线程 . 1.进程: 表示一个程序的执行活动 (打开程序.读写程序数据.关闭程序) 2.线程: 执行某个程序时, 该进程调度的最小执行单位 ...