[NOIP]2016天天爱跑步
[NOIP]2016天天爱跑步
标签: LCA 树上差分 NOIP
Description
小C同学认为跑步非常有趣,于是决定制作一款叫做《天天爱跑步》的游戏。《天天爱跑步》是一个养成类游戏,需要玩家每天按时上线,完成打卡任务。
这个游戏的地图可以看作一棵包含n个结点和n-1条边的树,每条边连接两个结点,且任意两个结点存在一条路径互相可达。树上结点编号为从1到n的连续正整数。
现在有m个玩家,第i个玩家的起点为Si,终点为Ti。每天打卡任务开始时,所有玩家在第0秒同时从自己的起点出发,以每秒跑一条边的速度,不间断地沿着最短路径向着自己的终点跑去,跑到终点后该玩家就算完成了打卡任务。(由于地图是一棵树,所以每个人的路径是唯一的)
Input
第一行有两个整数n和m。其中n代表树的结点数量,同时也是观察员的数量,m代表玩家的数量。
接下来n-1行每行两个整数u和v,表示结点u到结点v有一条边。
接下来一行n个整数,其中第j个整数为Wj,表示结点j出现观察员的时间。
接下来m行,每行两个整数Si和Ti,表示一个玩家的起点和终点。
对于所有的数据,保证1≤Si,Ti≤n,0≤ Wj ≤n。
Output
输出1行n个整数,第j个整数表示结点j的观察员可以观察到多少人。
Sample Input
6 3
2 3
1 2
1 4
4 5
4 6
0 2 5 1 2 3
1 5
1 3
2 6
Sample Output
2 0 0 1 1 1
Hint
提示:
对于1号点,W1=0,故只有起点为1号点的玩家才会被观察到,所以玩家1和玩家2被观察到,共2人被观察到。
对于2号点,没有玩家在第2秒时在此结点,共0人被观察到。
对于3号点,没有玩家在第5秒时在此结点,共0人被观察到。
对于4号点,玩家1被观察到,共1人被观察到。
对于5号点,玩家2被观察到,共1人被观察到。
对于6号点,玩家3被观察到,共1人被观察到。
Pic
如果你的程序需要用到较大的栈空间(这通常意味着需要较深层数的递归),请务必仔细阅读选手目录下的文档running/stackpdf,以了解在最终评测时栈空间的限制与在当前工作环境下调整栈空间限制的方法。
题解
- 对于一个玩家,他的路径我们可以拆成两段。分别是u->lca,lca->v。对于每一个观察者x,如果deep[x]+w[x]deep[u]时,u->lca的这段路径可能会更新答案。同理,deep[x]-w[x]deep[v]-dis(u,v)时,lca->v的这段路径也有可能更新答案。
- 我们只考虑u->lca,只有当x在u->lca上时,答案才会被更新。我们就很难统计。不过我们可以利用差分的思想,把这条路径拆成u->root(贡献为1),fa[lca]->root(贡献为-1),就容易统计一些了。
- 然后我们对树进行dfs,在dfs的过程中,对每一个子树的根u来说,遍历子树,再加上自己这个点的值,然后计算这个点被访问的次数,相当于求一遍前缀和,只是加上了自己所有子树的值。
Code
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define REP(i,a,b) for(int i=(a),_end_=(b);i<=_end_;i++)
#define DREP(i,a,b) for(int i=(a),_end_=(b);i>=_end_;i--)
#define EREP(i,a) for(int i=start[(a)];i;i=e[i].next)
inline int read()
{
int sum=0,p=1;char ch=getchar();
while(!(('0'<=ch && ch<='9') || ch=='-'))ch=getchar();
if(ch=='-')p=-1,ch=getchar();
while('0'<=ch && ch<='9')sum=sum*10+ch-48,ch=getchar();
return sum*p;
}
const int maxn=3e5+20;
struct node {
int v,next;
};
node e[maxn*2];
int cnt,start[maxn];
int n,m;
void addedge(int u,int v)
{
e[++cnt]={v,start[u]};
start[u]=cnt;
}
int deep[maxn],p[maxn][21];
void dfs(int u,int fa)
{
p[u][0]=fa;
EREP(i,u)
{
int v=e[i].v;
if(v==fa)continue;
deep[v]=deep[u]+1;
dfs(v,u);
}
}
int lca(int u,int v)
{
if(deep[u]<deep[v])swap(u,v);
DREP(i,20,0)if(p[u][i]!=-1 &&deep[p[u][i]]>=deep[v])u=p[u][i];
if(u==v)return u;
DREP(i,20,0)if(p[u][i]!=-1 && p[u][i]!=p[v][i])u=p[u][i],v=p[v][i];
return p[u][0];
}
struct player {
int t,w,next,id;
};
player ed[maxn*4];
int st[maxn],cn;
void add(int u,int t,int w,int idx)
{
ed[++cn]={t,w,st[u],idx};
st[u]=cn;
}
int A[maxn],B[maxn];
int ans[maxn];
int CntA[maxn*2],CntB[maxn*2];
void dfs1(int u,int fa)
{
int la=CntA[A[u]];
int lb=CntB[B[u]+maxn];
for(int i=st[u];i;i=ed[i].next)
{
int x=ed[i].t;
if(ed[i].id==1)
{
CntA[x]+=ed[i].w;
}else
{
CntB[x+maxn]+=ed[i].w;
}
}
EREP(i,u)
{
int v=e[i].v;
if(v==fa)continue;
dfs1(v,u);
}
int na=CntA[A[u]];
int nb=CntB[B[u]+maxn];
ans[u]+=(na-la)+(nb-lb);
}
void init()
{
n=read();m=read();
REP(i,1,n-1)
{
int u=read(),v=read();
addedge(u,v);
addedge(v,u);
}
deep[1]=1;
dfs(1,0);
REP(i,1,n)
{
int w=read();
A[i]=deep[i]+w;
B[i]=deep[i]-w;
}
REP(j,1,20)REP(i,1,n)p[i][j]=p[p[i][j-1]][j-1];
REP(i,1,m)
{
int u=read(),v=read(),Lca=lca(u,v);
int len=deep[u]+deep[v]-2*deep[Lca];//点用链表储存,方便调用
add(u,deep[u],1,1);
add(p[Lca][0],deep[u],-1,1);
add(v,deep[v]-len,1,2);
add(Lca,deep[v]-len,-1,2);
}
dfs1(1,0);
REP(i,1,n)
cout<<ans[i]<<" ";
}
int main()
{
freopen("input.in","r",stdin);
freopen("output.out","w",stdout);
init();
return 0;
}
[NOIP]2016天天爱跑步的更多相关文章
- NOIP 2016 天天爱跑步 80分暴力
题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 个结点 ...
- [NOIp 2016]天天爱跑步
Description 小C同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图 ...
- Noip 2016 天天爱跑步 题解
[NOIP2016]天天爱跑步 时间限制:2 s 内存限制:512 MB [题目描述] 小C同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是 ...
- NOIP 2016 天天爱跑步 (luogu 1600 & uoj 261) - 线段树
题目传送门 传送点I 传送点II 题目大意 (此题目不需要大意,我认为它已经很简洁了) 显然线段树合并(我也不知道哪来这么多显然) 考虑将每条路径拆成两条路径 s -> lca 和 t -> ...
- 【NOIP】提高组2016 天天爱跑步
[题意]n个点的树,有m个人同时开始走链,每一步花一秒,n个点都有观察员在ai秒观察,求每个观察员观察到的人数. [算法]树上差分(主席树||线段树合并) [题解]一个人的走链可以拆成u-lca和lc ...
- [luogu]P1600 天天爱跑步[LCA]
[luogu]P1600 [NOIP 2016]天天爱跑步 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上 ...
- 【NOIP 2016】Day1 T2 天天爱跑步
Problem Description 小 C 同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任 ...
- NOIP提高组2016 D1T2 【天天爱跑步】
码了一个下午加一个晚上吧...... 题目描述: 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成 ...
- [NOIP 2016D2T2/Luogu P1600] 天天爱跑步 (LCA+差分)
待填坑 Code //Luogu P1600 天天爱跑步 //Apr,4th,2018 //树上差分+LCA #include<iostream> #include<cstdio&g ...
随机推荐
- Linux下环境变量设置的三种方法
如想将一个路径加入到$PATH中,可以像下面这样做: 1.控制台中设置,不赞成这种方式,因为他只对当前的shell 起作用,换一个shell设置就无效了:$PATH="$PATH" ...
- linux 中nvme 的中断申请及处理
/** * struct irq_desc - interrupt descriptor * @irq_data: per irq and chip data passed down to chip ...
- 关于jwplayer 处理进度条禁止快进的处理方法。
今天在处理一个关于jwplayer 第一次播放禁止快进,但是可以后退的一个需求.开始在网上去查一些方法,有几个方法是换皮肤,禁止点击,但是和我的初衷不是很一致,还有一种方式是官网查看了API接口的方 ...
- JavaScript var的作用域和提升
在ES6标准之前,var 作为唯一的声明变量关键字,本篇将着重介绍var的作用域和变量提升. 1. var Hoisting(变量提升) va rHoisting:使用var在函数或全局内任何地方声明 ...
- python_19_异常处理
什么是异常处理? -- 对于用户输入,不想让用户看见出错信息,对异常进行处理 异常处理的框架是什么? try: 可能出错的程序1 可能出错的程序2 #程序1出错了,不在执行程序2 exc ...
- JavaScript数组的22种方法
原文:http://www.cnblogs.com/xiaohuochai/p/5682621.html javascript中数组的22种方法 前面的话 数组总共有22种方法,本文将其分为对象继 ...
- Django环境安装--Django从入门到精通系列教程
该系列教程系个人原创,并完整发布在个人官网刘江的博客和教程 所有转载本文者,需在顶部显著位置注明原作者及www.liujiangblog.com官网地址. Python及Django学习QQ群:453 ...
- css中 padding属性的数值赋予顺序为
4种可能的情况,举例说明:padding:10px; 四个内边距都是10pxpadding:5px 10px; 上下5px 左右10pxpadding:5px 10px 15px; 上5px 右10p ...
- python字符串问题
相关知识点: 字符串在Python内部的表示是unicode编码,因此,在做编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码(decode)成unicode,再从unico ...
- eclipse每次闪退后都提示查看\workspace\.metadata\.log
错误如下: 找到<workspace>/.metadata/.plugins/org.eclipse.e4.workbench/workbench.xmi"文件,将其删掉,再重启 ...