【NOIP2016】DAY1 T2 天天爱跑步
【NOIP2016】DAY1 T2 天天爱跑步
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
Solution
这道题目吧,好难……
首先,我们读入的是一棵树,在某些结点上有一些玩家(废话,读过题的都知道)
那么对于某一个玩家, 其实在树的某条链上有两种情况,一种是从下向上,另一种是从上向下,即该玩家还没走到起点和终点的lca,另一种已经过了起点和终点的lca(我废话真多)
我们先对于其中一种情况讨论,当该点从下向上时(我不会说是因为这种情况比较简单),如图P1,我们可以看出当且仅当w[i]+d[i]=d[x]时,从x出发的玩家才能被在i点的观察员观察到(d[i]表示结点i的深度),那么当该点从上向下时呢?我们看P2,显然当且仅当d[y]-d[i]=dis(x,y)-w[i](dis(x,y)表示x与y之间的距离)我们把这个式子变形一下,w[i]-d[i]=dis(x,y)-d[y](当然这个式子也可以写成w[i]-d[i]=d[x]-2*d[lca(x,y)],因为dis(x,y)=d[x]+d[y]-2*d[lca(x,y)])
P1 P2
现在我们遇上了一个大问题,这两个式子如何来实现?
利用一个高档货,树上差分(不知道哪里高档,反正就是高档就对了),我们便可以在x上+1,在lca(x,y)上-1,对于y也相同,在y上+1,在lca(x,y)上-1,当我们对于这棵树dfs的时候,遍历到i时,利用差分就可以做到求出在i的子树中的能走到i的玩家数
可是我们要求的不仅仅是玩家经过该点,还需在同一时刻出现,其实我们只要做两个桶就可以了,桶p[k]记录起点的d[x]=k的玩家数量,桶q[k]记录终点的dis(x,y)-d[y]=k的玩家数量,对于每个点的答案就是q[d[i]+w[i]]+p[w[i]-d[i]]-这个点遍历前q[d[i]+w[i]]+p[w[i]-d[i]](因为有些玩家从该点的祖先开始或结束但还没走到lca),当然我们需要记录以某个结点开始的玩家和以某个结束的玩家(这句话别看,因为我看了也懵,看下下面程序再结合一下这句话大概应该可能就可以看懂了吧)
还有一个小问题,就是当w[lca(x,y)]+d[lca(x,y)]==d[x]时,我们会发现向上走和向下走都会对lca有贡献,所以当lca可以观测到时我们需要把lca处的答案-1
但是还有一个坑,就是w[i]-d[i]可能小于0,那就把桶里面的数都加300000就可以了
讲得好水,看下程序吧(虽然说很丑)
#include<cstdio>
#include<utility>
struct r{
int to,last,w;
}e[],in1[],ou1[],in2[],ou2[];
int num=,num1=,num2=,num3=,num4=,head[],head1[],head2[],
head3[],head4[],w[],d[],f[][],ans[];
void add(int u,int v){
e[num].to=v;
e[num].last=head[u];
head[u]=num++;
}
void add_edge(int u,r &p,int*q,int&num,int w){
p.w=w;
p.last=q[u];
q[u]=num++;
}
inline int readin(){
int c=getchar(),ret=;
while (c<''||c>'') c=getchar();
while (c>=''&&c<='') ret=(ret<<)+(ret<<)+c-'',c=getchar();
return ret;
}
void dfs(int k,int fa){
d[k]=d[fa]+;
f[k][]=fa;
for (int i=;i<=;i++) f[k][i]=f[f[k][i-]][i-];
for (int i=head[k];i;i=e[i].last)if (e[i].to!=fa){
dfs(e[i].to,k);
}
}
int lca(int u,int v){
if (d[u]>d[v]) std::swap(u,v);
int y=d[v]-d[u];
for (int i=;i>=;i--) if ((y&(<<i))) v=f[v][i];
if (u==v) return u;
for (int i=;i>=;i--) if (f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i];
return f[u][];
}
int q[],p[];
void dfs2(int k,int fa){
int req=q[d[k]+w[k]],rep=p[w[k]-d[k]+];
for (int i=head1[k];i;i=in1[i].last) q[in1[i].w]++;
for (int i=head3[k];i;i=in2[i].last) p[in2[i].w]++;
for (int i=head[k];i;i=e[i].last) if (e[i].to!=fa) dfs2(e[i].to,k);
ans[k]+=q[d[k]+w[k]]-req+p[w[k]-d[k]+]-rep;
for (int i=head2[k];i;i=ou1[i].last) q[ou1[i].w]--;
for (int i=head4[k];i;i=ou2[i].last) p[ou2[i].w]--;
}
int main()
{
int n=readin(),m=readin(),u,v,x,y;
for (int i=;i<n;i++) u=readin(),v=readin(),add(u,v),add(v,u);
num=;
dfs(,);
for (int i=;i<=n;i++) w[i]=readin();
for (int i=;i<=m;i++){
x=readin(),y=readin();
int z=lca(x,y);
if (d[x]==d[z]+w[z]) ans[z]--;
add_edge(x,in1[num1],head1,num1,d[x]),
add_edge(z,ou1[num2],head2,num2,d[x]),
add_edge(y,in2[num3],head3,num3,d[x]-d[z]*+),
add_edge(z,ou2[num4],head4,num4,d[x]-d[z]*+);
}
dfs2(,);
for (int i=;i<=n;i++)
printf("%d ",ans[i]);
return ;
}
【NOIP2016】DAY1 T2 天天爱跑步的更多相关文章
- [NOIP2016 DAY1 T2]天天爱跑步-[差分+线段树合并][解题报告]
[NOIP2016 DAY1 T2]天天爱跑步 题面: B[NOIP2016 DAY1]天天爱跑步 时间限制 : - MS 空间限制 : 565536 KB 评测说明 : 2s Description ...
- Luogu P1600[NOIP2016]day1 T2天天爱跑步
号称是noip2016最恶心的题 基本上用了一天来搞明白+给sy讲明白(可能还没讲明白 具体思路是真的不想写了(快吐了 如果要看,参见洛谷P1600 天天爱跑步--题解 虽然这样不好但我真的不想写了 ...
- NOIP2016 DAY1 T2天天爱跑步
传送门 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 ...
- NOIP2016 Day1 T2 天天爱跑步(树上差分,LCA)
原文链接 原题链接 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏 ...
- 【NOIP 2016】Day1 T2 天天爱跑步
Problem Description 小 C 同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任 ...
- 【NOIP2016 Day1 T2】天天爱跑步
题目传送门:https://www.luogu.org/problemnew/show/P1600 感觉这两天在处理边界问题上有点神志不清......为了从80的暴力变成100,花了整整一个下午+一个 ...
- [NOIp2016提高组]天天爱跑步
题目大意: 有一棵n个点的树,每个点上有一个摄像头会在第w[i]秒拍照. 有m个人再树上跑,第i个人沿着s[i]到t[i]的路径跑,每秒钟跑一条边. 跑到t[i]的下一秒,人就会消失. 问每个摄像头会 ...
- P1600 [NOIP2016 提高组] 天天爱跑步 (树上差分)
对于一条路径,s-t,位于该路径上的观察员能观察到运动员当且仅当以下两种情况成立:(d[ ]表示节点深度) 1.观察员x在s-lca(s,t)上时,满足d[s]=d[x]+w[x]就能观察到,所以我们 ...
- [luogu]P1600 天天爱跑步[LCA]
[luogu]P1600 [NOIP 2016]天天爱跑步 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上 ...
随机推荐
- web视频播放插件:Video For Everybody
相比其它的web视频播放插件(video.js , jwplayer等)来说,Video For Everybody(极力推荐)是一款更好的视频播放插件,无需任何下载,支持html5以及flash播放 ...
- How to read and write multiple files in Python?
Goal: I want to write a program for this: In a folder I have =n= number of files; first read one fil ...
- 洛谷 1097 统计数字(NOIp2007提高组T1)
[题解] 排个序然后扫一遍进行统计即可. #include<cstdio> #include<algorithm> #include<cstring> #defin ...
- Python基础—面向对象(初级篇)
一.什么是面向对象编程 面向对象编程(Object Oriented Programming,OOP,面向对象程序设计),python语言比较灵活即支持面向对象编程也支持面向函数式编程. 面向过程编程 ...
- noip模拟赛 兔子
[问题描述]在一片草原上有N个兔子窝,每个窝里住着一只兔子,有M条路径连接这些窝.更特殊地是,至多只有一个兔子窝有3条或更多的路径与它相连,其它的兔子窝只有1条或2条路径与其相连.换句话讲,这些兔子窝 ...
- 在JQuery中$(document.body)和这个$("body") 这两的区别在哪里?
两种写法代表的是同一个对象 $("body") 是一个选择器,jQuery 会从 DOM 顶端开始搜索,直到找到标签为 body 的元素. 而 $(document.body) 中 ...
- 【整理】uclibc,eglibc,glibc之间的区别和联系
http://www.crifan.com/relation_between_uclibc_glibc_eglibc/ 1.Glibc glibc = GNU C Library 是GNU项(GNU ...
- 如何让图片开口说话 3DMeNow教程
菜鸟玩3D--3DmeNow初级教程 3D软件对于我们这些菜鸟来说,一直是可望而不可及的一种东西,深奥的3D建模,复杂的面板操作--都使我们对之望而却步,有没有一种很简单的3D造型软件,使我们这些菜鸟 ...
- git-svn for mac
熟练使用 git ,新公司用的是 svn,这就尴尬了,为了这个习惯问题,我还是毅然坚持使用 git,但是又不与公司的 svn 冲突,所以就找到了 git 的 git-svn 插件. 在 mac 上使用 ...
- kentico11 教程,
create master page with css list menu Add the navigation menu Add a dynamic web part that will repre ...