【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同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上 ...
随机推荐
- 热词解析(9) — hangry
今天给大家介绍一个非常有趣.又超级实用的词!!中文叫"饿极而怒",英文叫... 不知道你有没有这样的经历,当你饿着肚子等着你妈做饭,结果你妈却在麻将桌上不下来,你就越来越饿,越饿越 ...
- day21 01 包的初识
day21 01包的初识 包:把解决一类问题的模块放在同一个文件夹里面-----包(一个包里面通常会含有_init_.py文件(python2里面必须有),但是后面的就没有要求一定要有了) 同样导入的 ...
- Django DTL模板语法中的url反转
"""template_url_demo URL Configuration The `urlpatterns` list routes URLs to views. F ...
- 微信小程序-template模板
============================= 构建template模板 ============================= 1.分析得出共为 ...
- 【05】JSON笔记
[05]笔记 尽管有许多宣传关于 XML 如何拥有跨平台,跨语言的优势,然而,除非应用于 Web Services,否则,在普通的 Web 应用中,开发者经常为 XML 的解析伤透 ...
- 【04】JSONP 教程
JSONP 教程 Jsonp(JSON with Padding) 是 json 的一种"使用模式",可以让网页从别的域名(网站)那获取资料,即跨域读取数据. 为什么我们从不同的域 ...
- 【Codeforces 986B】Petr and Permutations
[链接] 我是链接,点我呀:) [题意] 题意 [题解] n为奇数时3n和7n+1奇偶性不同 n为偶数时也是如此 然后交换任意一对数 逆序对的对数的奇偶性会发生改变一次 求出逆序对 对n讨论得出答案. ...
- 【MongoDB】2、安装MongoDB 2.6.1 on Unbuntu 14.04(学习流水账)
http://blog.csdn.net/stationxp/article/details/26077439 计划: 装一个虚机,ubuntu吧,14.04 Trusty Tahr. 安装Mongo ...
- md5加密的工具类(from 韩顺平)
输入一个字符串,然后可以进行md5加密 import java.security.*; import java.security.spec.*; public class MyTools { publ ...
- Ubuntu 16.04安装PPA图形化管理工具Y PPA Manager
安装: sudo add-apt-repository ppa:webupd8team/y-ppa-manager sudo apt-get update sudo apt-get install y ...