Description

小c同学认为跑步非常有趣,于是决定制作一款叫做《天天爱跑步》的游戏。《天天爱跑步》是一个养成类游戏,需要
玩家每天按时上线,完成打卡任务。这个游戏的地图可以看作一一棵包含 N个结点和N-1 条边的树, 每条边连接两
个结点,且任意两个结点存在一条路径互相可达。树上结点编号为从1到N的连续正整数。现在有个玩家,第个玩家的
起点为Si ,终点为Ti  。每天打卡任务开始时,所有玩家在第0秒同时从自己的起点出发, 以每秒跑一条边的速度,
不间断地沿着最短路径向着自己的终点跑去, 跑到终点后该玩家就算完成了打卡任务。 (由于地图是一棵树, 所以
每个人的路径是唯一的)小C想知道游戏的活跃度, 所以在每个结点上都放置了一个观察员。 在结点的观察员会选
择在第Wj秒观察玩家, 一个玩家能被这个观察员观察到当且仅当该玩家在第Wj秒也理到达了结点J  。 小C想知道
每个观察员会观察到多少人?注意: 我们认为一个玩家到达自己的终点后该玩家就会结束游戏, 他不能等待一 段时
间后再被观察员观察到。 即对于把结点J作为终点的玩家: 若他在第Wj秒重到达终点,则在结点J的观察员不能观察
到该玩家;若他正好在第Wj秒到达终点,则在结点的观察员可以观察到这个玩家。

Input

第一行有两个整数N和M 。其中N代表树的结点数量, 同时也是观察员的数量, M代表玩家的数量。
接下来n-1 行每行两个整数U和V ,表示结点U 到结点V 有一条边。
接下来一行N 个整数,其中第个整数为Wj , 表示结点出现观察员的时间。
接下来 M行,每行两个整数Si和Ti,表示一个玩家的起点和终点。
对于所有的数据,保证 。
1<=Si,Ti<=N,0<=Wj<=N

Output

输出1行N 个整数,第个整数表示结点的观察员可以观察到多少人。

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
 

lydrainbowcat讲的真是炒鸡棒啊,这里主要参考他在sfjsjjzn上的讲解

首先,每个玩家跑步的路线可以分成两部分:$S$->$lca(S,T)$  $lca(S,T)$->$T$,后者不包括lca

那么,如果位于节点x的观察员能看到玩家i,当且仅当满足:

1.x在S到lca的路径上,且满足$dep[S_i]-dep[x]=w[x]$

2.x在lca到T的路径上(不含lca),且满足$dep[S_i]+dep[x]-2*dep[lca]=w[x]$

接下来分开计算这两种观察员,最后相加即可

首先看一道题

我们的这道题也可以转化成“路径上投放物品”的问题

以第一种观察员的情况为例

由$dep[S_i]-dep[x]=w[x]$

可得$dep[S_i]=dep[x]+w[x]$

就可以理解为给S到lca的路径上的每个点添加类型为$dep[S_i]$的物品

所求为每个点$w[x]+dep[x]$类型的物品有多少

使用树上差分,将其转化为:

点S处生成物品$dep[S_i]$,点lca处这种物品消失

同理,第二种观察员可以转化为$dep[S_i]-2*dep[lca]$在T生成,在lca消失

所求为$w[x]-dep[x]$的物品数量

权值线段树合并确实是可以的,但本题不需要维护最值,只是求特定数量

所以可以对每个点开vector,把物品的生成和消失记录存在里面

最后统计的时候  开一个数组cnt[]用于统计数量(不是每个点开一个!运用差分的思想!)

递归时先存一下旧的$c[所求]$,回溯的时候用新的值减去它

即为子树和

最后每个点的答案即为两种情况相加

自认为代码可读性还是很高的:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
const int N=;
int n,m,to[N<<],nxt[N<<],head[N],fa[N][],tot=;
int w[N],dep[N],cnt1[N<<],cnt2[N<<],ans1[N],ans2[N];
vector<int> sp[][N],del[][N];
inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>'')
{if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<='')
{x=(x<<)+(x<<)+ch-'';ch=getchar();}
return x*f;
}
void add(int x,int y)
{
to[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
void dfs(int x,int deep)
{
dep[x]=deep;
for(int i=;i<=;i++)
fa[x][i]=fa[fa[x][i-]][i-];
for(int i=head[x];i;i=nxt[i])
{
if(dep[to[i]])continue;
fa[to[i]][]=x;
dfs(to[i],deep+);
}
}
int LCA(int x,int y)
{
if(dep[x]>dep[y])swap(x,y);
for(int i=;i>=;i--)
if(dep[fa[y][i]]>=dep[x])y=fa[y][i];
if(x==y)return x;
for(int i=;i>=;i--)
if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
return fa[x][];
}
void spawn(int pos,int val,int k)
{
sp[k][pos].push_back(val);
}
void remove(int pos,int val,int k)
{
del[k][pos].push_back(val);
}
void cacl1(int x)
{
int now=cnt1[w[x]+dep[x]+n];
for(int i=;i<(int)sp[][x].size();i++)
cnt1[sp[][x][i]]++;
for(int i=;i<(int)del[][x].size();i++)
cnt1[del[][x][i]]--;
for(int i=head[x];i;i=nxt[i])
if(dep[to[i]]>dep[x])cacl1(to[i]);
ans1[x]=cnt1[w[x]+dep[x]+n]-now;
}
void cacl2(int x)
{
int now=cnt2[w[x]-dep[x]+n];
for(int i=;i<(int)sp[][x].size();i++)
cnt2[sp[][x][i]]++;
for(int i=;i<(int)del[][x].size();i++)
cnt2[del[][x][i]]--;
for(int i=head[x];i;i=nxt[i])
if(dep[to[i]]>dep[x])cacl2(to[i]);
ans2[x]=cnt2[w[x]-dep[x]+n]-now;
}
int main()
{
n=read();m=read();
for(int i=;i<n;i++)
{
int x=read(),y=read();
add(x,y);add(y,x);
}
for(int i=;i<=n;i++)
w[i]=read();
dfs(,);
for(int i=;i<=m;i++)
{
int S=read(),T=read(),lca=LCA(S,T);
spawn(S,dep[S]+n,);
remove(fa[lca][],dep[S]+n,);
spawn(T,dep[S]-*dep[lca]+n,);
remove(lca,dep[S]-*dep[lca]+n,);
}
cacl1();
cacl2();
for(int i=;i<=n;i++)
printf("%d ",ans1[i]+ans2[i]);
return ;
}

在自家oj上用时是最慢ac的一半,可以说是性价比极高了?

[NOIP2016]天天爱跑步 题解(树上差分) (码长短跑的快)的更多相关文章

  1. [luogu1600 noip2016] 天天爱跑步 (树上差分)

    题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵 ...

  2. ☆ [NOIp2016] 天天爱跑步 「树上差分」

    题目类型:LCA+思维 传送门:>Here< 题意:给出一棵树,有\(M\)个人在这棵树上跑步.每个人都从自己的起点\(s[i]\)跑到终点\(t[i]\),跑过一条边的时间为1秒.现在每 ...

  3. bzoj 4719: [Noip2016]天天爱跑步【树上差分+dfs】

    长久以来的心理阴影?但是其实非常简单-- 预处理出deep和每组st的lca,在这里我简单粗暴的拿树剖爆算了 然后考虑对于一组s t lca来说,被这组贡献的观察员x当且仅当: x在s到lca的路径上 ...

  4. NOIP2016 天天爱跑步(树上差分)

    题意 给定一棵树,从时刻 0 开始,有若干人从 S[i] 出发向 T[i] 移动,每单位时刻移动一条边 对于树上每个点 x,求 w[x]  时刻有多少人恰好路过 x N,M≤300000 题解 从上午 ...

  5. NOIP2016天天爱跑步 题解报告【lca+树上统计(桶)】

    题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 nn个 ...

  6. 【NOIP2016】天天爱跑步(树上差分)

    题意: 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要 玩家每天按时上线,完成打卡任务.这个游戏的地图可以看作一一棵包含 N个结点 ...

  7. [NOIP2016]天天爱跑步-题解

    题面传送门 解答 设第\(j\)号玩家在\(V_j\)时刻出发. 弱化问题:如果树退化成了一条链.则在\(j\)处的观察员能观察到的\(i\)号玩家当且仅当 \[ i玩家经过j,且 \begin{ca ...

  8. LOJ2359. 「NOIP2016」天天爱跑步【树上差分】

    LINK 思路 首先发现如果对于一个节点,假设一个节点需要统计从字数内来的贡献 需要满足\(dep_u - dep_s = w_u\) 这个条件其实可以转化成\(dep_u - w_u = dep_s ...

  9. P1600 [NOIP2016 提高组] 天天爱跑步 (树上差分)

    对于一条路径,s-t,位于该路径上的观察员能观察到运动员当且仅当以下两种情况成立:(d[ ]表示节点深度) 1.观察员x在s-lca(s,t)上时,满足d[s]=d[x]+w[x]就能观察到,所以我们 ...

随机推荐

  1. Linux系统之-文件系统,桌面环境

    文件系统 文件类型普通文件,目录文件,连接文件,设备与设备文件,套接字,管道 普通文件(regular file):就是一般存取的文件,由ls -al显示出来的属性中,第一个属性为 [-],例如 [- ...

  2. BZOJ 1005: [HNOI2008]明明的烦恼(高精度+prufer序)

    传送门 解题思路 看到度数和生成树个树,可以想到\(prufer\)序,而一张规定度数的图的生成树个数为\(\frac{(n-2)!}{\prod\limits_{i=1}^n(d(i)-1)!}\) ...

  3. python(列表推导式和生成器表达式)

    从母鸡下蛋的故事讲起 老母鸡 = ('鸡蛋%s'%i for i in range(10)) print(老母鸡) for 蛋 in 老母鸡: print(蛋) g = (i*i for i in r ...

  4. QTP学习笔记--define new test object

    目前在测的系统里,有图片控件,图片源都是一样的,链接地址不同(链接地址是动态变化的,不适合作为属性). QTP的识别机制是根据Index来的,复制对象之后更改Index的属性方法无效,采用define ...

  5. mysql left join 用法说明

    left join中关于where和on条件的几个知识点: 1.多表left join是会生成一张临时表,并返回给用户 2.where条件是针对最后生成的这张临时表进行过滤,过滤掉不符合where条件 ...

  6. Linux命令 uname

    1.简介 管理系统而使用的命令,用于显示系统信息(不同linux版本可能有写差异) 2.语法 uname [-amnrsv] (1) -a,--all 显示所有的信息 (2) -s,--kernel- ...

  7. jwt认证登录

    配置文件:#服务配置 server: port: 9002 #spring配置 spring: #应用配置 application: name: ynhrm-system #指定服务名 #数据库连接池 ...

  8. Java SAX解析器

    SAX(针对XML的简单API)是基于事件为XML文档的解析器.不像DOM解析器,SAX解析器创建没有解析树. SAX是一个流接口用于XML的,这意味着使用SAX应用接收事件通知有关XML文档被处理的 ...

  9. ajaxfileupload上传文件出现SyntaxError:unexpected token <错误

    function ajaxFileUpload() { $.ajaxFileUpload ( { url: uri, secureuri: false, fileElementId: 'upFile' ...

  10. LeetCode Array Easy169. Majority Element

    Description Given an array of size n, find the majority element. The majority element is the element ...