【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同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上 ...
随机推荐
- CCF201512-2 消除类游戏 java(100分)
试题编号: 201512-2 试题名称: 消除类游戏 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 消除类游戏是深受大众欢迎的一种游戏,游戏在一个包含有n行m列的游戏棋盘上进 ...
- CCF201703-1 分蛋糕 java(100分)
试题编号: 201703-1 试题名称: 分蛋糕 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 小明今天生日,他有n块蛋糕要分给朋友们吃,这n块蛋糕(编号为1到n)的重量分别 ...
- Centos下Yum安装PHP5.5,5.6,7.0及扩展
默认的版本太低了,手动安装有一些麻烦,想采用Yum安装的可以使用下面的方案: 1.检查当前安装的PHP包 yum list installed | grep php 如果有安装的PHP包,先删除他们 ...
- python3中整数和小数的转换
在整数除法中,除法(/)总是返回一个浮点数,如果只想得到整数的结果,丢弃可能的分数部分,可以使用运算符 // : >>> 17 / 3 # 整数除法返回浮点型 5.666666666 ...
- stall and flow separation on airfoil or blade
stall stall and flow separation Table of Contents 1. Stall and flow separation 1.1. Separation of Bo ...
- java属性的默认值
String 默认null Boolean默认false int默认0 double默认0.0 类中使用自定义类定义属性默认值:null 在定义属性的时候可以指定默认值
- Mongodb学习总结(2)——MongoDB与MySQL区别及其使用场景对比
对于只有SQL背景的人来说,想要深入研究NoSQL似乎是一个艰巨的任务,MySQL与MongoDB都是开源常用数据库,但是MySQL是传统的关系型数据库,MongoDB则是非关系型数据库,也叫文档型数 ...
- [luoguP2915] [USACO08NOV]奶牛混合起来Mixed Up Cows(DP)
传送门 f[i][S] 表示当前集合为 S,最后一个数为 i 的最优解 f[i][S] += f[j][S - i] (j, i ∈ S && j != i && ab ...
- 洛谷—— P1825 [USACO11OPEN]玉米田迷宫Corn Maze
https://www.luogu.org/problem/show?pid=1825 题目描述 This past fall, Farmer John took the cows to visit ...
- 洛谷——P2910 [USACO08OPEN]寻宝之路Clear And Present Danger
P2910 [USACO08OPEN]寻宝之路Clear And Present Danger 题目描述 Farmer John is on a boat seeking fabled treasur ...