原文链接https://www.cnblogs.com/zhouzhendong/p/9275606.html

题目传送门 - 洛谷P1600

题目传送门 - LOJ#2359

题目传送门 - Vijos P2004

题意

  给定一个有 $n$ 个节点的树,每一个节点有一个观察员,编号为 $i$ 的节点上的观察员会在 $W_i$ 时刻出来观察。

  现在有 $m$ 个热爱健身的人,其中第 $i$ 个从节点 $S_i$ 开始,到 $T_i$ 结束。

  从时刻 $0$ 开始,每一个人同时以每秒一条边的速度沿着他的起点终点的最短路径移动,移到 $T_i$ 时停止移动,然后下一秒“消失”。

  对于每一个节点,问在哪个位置的观察员会观察到几个人。

  数据范围:

  $1\leq n<300000,0\leq W_i\leq n,1\leq S_i,T_i\leq n$

题解

  看到原题中有一档链上询问的部分分,于是我们先考虑链上的情况。

  对于所有 $S_i\leq T_i$ ,我们发现第 $i$ 个人到达第 $j$ 个节点时, $T-j$ 为定值。(其中 $T$ 为当前的时间)

  即,若存在 $j$ 节点上面的观察员看到了这个人,那么必然有:

$$0-S_i=W_j-j=(T_i-S_i)-T_i$$

  那么我们只需要差分一下,用一个桶维护,在 $S_i$ 时给桶的 $0-S_i$ 位置加上 $1$ ,然后在 $T_i+1$ 位置减掉就可以了。

  于是我们只需要对于每一个 $i$ ,预处理一下要在桶上面进行的操作,给每一个点开一个 vector ,把需要的操作扔进去即可。

  然后顺着一遍扫过去处理,对第 $i$ 个节点的贡献就是 $Tax[W_i-i]$ 。

  

  对于所有 $S_i>T_i$ ,类似的,我们发现第 $i$ 个人到达第 $j$ 个节点时,$T+j$ 为定值。

  和上面类似的,我们可以完成这一部分的贡献。

  于是我们就可以解决链上的本问题了。

  时间复杂度 $\Theta(n)$ 。

  而原问题是在树上。

  那就树链剖分一下就可以了。

  复杂度多一只 $log$ ,因为每一条路径被分成了 $O(\log n)$ 条,对应的有 $O(n\log n)$ 个操作,每一个操作 $O(1)$。

  为了方便,我们用倍增求 $LCA$ 。当然写的时候一定要有清醒的头脑,千万注意细节。

  时空复杂度 $\Theta(n\log n)$ 。

代码

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <bits/stdc++.h>
#define dec D
using namespace std;
const int N=600005;
struct Gragh{
int cnt,y[N],nxt[N],fst[N];
void add(int a,int b){
y[++cnt]=b,nxt[cnt]=fst[a],fst[a]=cnt;
}
}g;
int n,m;
int fa[N][20],depth[N],size[N],son[N],top[N],p[N],ap[N],cnp=0;
int wtime[N],ans[N],itax[N],dtax[N];
vector <int> inc[N],dec[N];
void Get_Gen_Info(int x,int pre,int d){
depth[x]=d,fa[x][0]=pre,son[x]=-1,size[x]=1;
for (int i=1;i<20;i++)
fa[x][i]=fa[fa[x][i-1]][i-1];
for (int i=g.fst[x];i;i=g.nxt[i])
if (g.y[i]!=pre){
int y=g.y[i];
Get_Gen_Info(y,x,d+1);
size[x]+=size[y];
if (son[x]==-1||size[y]>size[son[x]])
son[x]=y;
}
}
void Get_Top(int x,int Top){
top[x]=Top;
ap[p[x]=++cnp]=x;
if (son[x]==-1)
return;
Get_Top(son[x],Top);
for (int i=g.fst[x];i;i=g.nxt[i]){
int y=g.y[i];
if (y!=fa[x][0]&&y!=son[x])
Get_Top(y,y);
}
}
int LCA(int x,int y){
if (depth[x]<depth[y])
swap(x,y);
for (int i=19;i>=0;i--)
if (depth[x]-(1<<i)>=depth[y])
x=fa[x][i];
if (x==y)
return x;
for (int i=19;i>=0;i--)
if (fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
void Tupdate(int S,int T){
int TS=0,TT=depth[S]+depth[T]-2*depth[LCA(S,T)];
int FS=top[S],FT=top[T];
while (FS!=FT)
if (depth[FS]>depth[FT]){
dec[p[FS]].push_back(TS+p[S]);
dec[p[S]+1].push_back(-(TS+p[S]));
TS+=depth[S]-depth[FS]+1;
S=fa[FS][0],FS=top[S];
}
else {
inc[p[FT]].push_back(TT-p[T]+n+1);
inc[p[T]+1].push_back(-(TT-p[T]+n+1));
TT-=depth[T]-depth[FT]+1;
T=fa[FT][0],FT=top[T];
}
if (depth[S]>depth[T]){
dec[p[T]].push_back(TT+p[T]);
dec[p[S]+1].push_back(-(TS+p[S]));
}
else {
inc[p[S]].push_back(TS+n-p[S]+1);
inc[p[T]+1].push_back(-(TT+n-p[T]+1));
}
}
int main(){
scanf("%d%d",&n,&m);
for (int i=1,a,b;i<n;i++)
scanf("%d%d",&a,&b),g.add(a,b),g.add(b,a);
for (int i=1;i<=n;i++)
scanf("%d",&wtime[i]);
Get_Gen_Info(1,0,0);
Get_Top(1,1);
for (int i=1,S,T;i<=m;i++)
scanf("%d%d",&S,&T),Tupdate(S,T);
for (int i=1;i<=n;i++){
for (int j=0;j<inc[i].size();j++){
int v=inc[i][j],d=1;
if (v<0)
v=-v,d=-d;
itax[v]+=d;
}
for (int j=0;j<dec[i].size();j++){
int v=dec[i][j],d=1;
if (v<0)
v=-v,d=-d;
dtax[v]+=d;
}
int x=ap[i];
ans[x]=itax[wtime[x]+(n-i+1)]+dtax[wtime[x]+i];
}
for (int i=1;i<=n;i++)
printf("%d ",ans[i]);
return 0;
}

  

NOIP2016提高组Day1T2 天天爱跑步 树链剖分 LCA 倍增 差分的更多相关文章

  1. BZOJ4719[NOIP2016提高组Day1T2] 天天爱跑步

    #261. [NOIP2016]天天爱跑步 描述 提交 自定义测试 小C同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家 ...

  2. NOIP2015 运输计划 - 二分 + 树链剖分 / (倍增 + 差分)

    BZOJ CodeVS Uoj 题目大意: 给一个n个点的边带权树,给定m条链,你可以选择树中的任意一条边,将它置为0,使得最长的链长最短. 题目分析: 最小化最大值,二分. 二分最短长度mid,将图 ...

  3. NOIP2016提高组D1T2 天天爱跑步

    n<=300000个点的树,每个点有个人于第Ti秒观测,有m<=300000个人于时间0开始从Sj跑到Tj,速度1个点每秒,输出每个点上的人观察到的跑步的人的数量. 前25分:直接模拟每条 ...

  4. BZOJ 4719 [Noip2016]天天爱跑步 ——树链剖分

    一直以为自己当时是TLE了,但是再看发现居然WA? 然后把数组扩大一倍,就A掉了.QaQ 没什么好说的.一段路径分成两段考虑,上升的一段深度+时间是定值,下降的一段深度-时间是定值,然后打标记统计即可 ...

  5. 树链剖分与倍增求LCA

    树链剖分与倍增求\(LCA\) 首先我要吐槽机房的辣基供电情况,我之前写了一上午,马上就要完成的时候突然停电,然后\(GG\)成了送链剖分 其次,我没歧视\(tarjan LCA\) 1.倍增求\(L ...

  6. CodeForces 916E Jamie and Tree(树链剖分+LCA)

    To your surprise, Jamie is the final boss! Ehehehe. Jamie has given you a tree with n vertices, numb ...

  7. 【BZOJ】2819: Nim(树链剖分 / lca+dfs序+树状数组)

    题目 传送门:QWQ 分析 先敲了个树链剖分,发现无法AC(其实是自己弱,懒得debug.手写栈) 然后去学了学正解 核心挺好理解的,$ query(a) $是$ a $到根的异或和. 答案就是$ l ...

  8. POJ - 2763 Housewife Wind (树链剖分/ LCA+RMQ+树状数组)

    题意:有一棵树,每条边给定初始权值.一个人从s点出发.支持两种操作:修改一条边的权值:求从当前位置到点u的最短路径. 分析:就是在边可以修改的情况下求树上最短路.如果不带修改的话,用RMQ预处理LCA ...

  9. BZOJ 3083 遥远的国度(树链剖分+LCA)

    Description 描述zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要z ...

随机推荐

  1. delhpi:http超时设置(转载)

    原文地址:http://www.delphitop.com/html/kongjian/544.html var FHTTPClient:TIdHTTP; begin FHTTPClient := T ...

  2. appium+java(五)微信小程序自动化测试实践

    前言: 上一篇<appium+java(四)微信公众号自动化测试实践>中,尝试使用appium实现微信公众号自动化测试,接着尝试小程序自动化,以学院小程序为例 准备工作 1.java-cl ...

  3. 正版phpstorm,webstorm,goland(Jetbrains系列都可以)免费激活步骤(图文详解)(亲测有效)

    1 前言 Jetbrains系列都可以,包括webstrom,phpstorm,goland等. 附加其它方案如下: webstrom(注册机) goland(破解补丁) 2 步骤 1. 可以先试用, ...

  4. [转]MySQL常用Json函数和MySQL常用字符串函数

    MySQL常用Json函数:https://www.cnblogs.com/waterystone/p/5626098.html MySQL常用字符串函数:https://www.cnblogs.co ...

  5. oracle 报表带小计合计

    selectcase when (grouping(glbm)=1) then '合计' else DECODE(glbm,null,'',glbm) end glbm,case when (grou ...

  6. 访问 Confluence 6 的计划任务配置

    希望访问 Confluence 计划任务配置界面: 进入  > 基本配置(General Configuration) > 计划任务(Scheduled Jobs) 所有的计划任务将会按照 ...

  7. Confluence 6 修改日志文件的大小数量和级别

    修改日志文件的大小和数量 在默认的情况下,Confluence 将会保持 5 个日志文件,每一个日志文件的大小超过 20 MB 的时候将会被重写. 你可以修改默认日志文件的大小和数量,通过编辑 < ...

  8. 初始Ajax

    一.Ajax准备知识:json 说起json,我们大家都了解,就是python中的json模块,那么json模块具体是什么呢?那我们现在详细的来说明一下 1.json(Javascript  Obie ...

  9. 前端基础之初识HTML

    一.web服务的本质 import socket def main(): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.b ...

  10. lightoj1214 大数取模模板

    #include<bits/stdc++.h> using namespace std; #define maxn 300 #define ll long long ll a,b; ]; ...