原文链接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. Mysql按条件计数的几种方法

    最近在给某网站的后台添加一系列的统计功能,遇到很多需要按条件计数的情况.尝试了几种方法,下面简要记录,供大家参考. 问题描述 为使讨论简单易懂,我将问题稍作简化,去掉诸多的背景. 从前有一个皇帝,他有 ...

  2. Android中验证输入是否为汉字、手机号及邮箱

    1,验证是否为汉字 Code// 验证昵称 private boolean verifyNickname() { String nickname = edt_username.getText().to ...

  3. UML建模图

    UML 2.0规范 迅速成为建立软件系统可视化.规范.文档的标准.统一建模语言(UML) 也被用于非软件系统的建模,并在很多领域,诸如金融,军事,工程方面应用广泛. UML 2 定义了13种基本的图, ...

  4. 【原创】大叔问题定位分享(33)beeline连接presto报错

    hive2.3.4 presto0.215 使用hive2.3.4的beeline连接presto报错 $ beeline -d com.facebook.presto.jdbc.PrestoDriv ...

  5. AGC 014 E Blue and Red Tree [树链剖分]

    传送门 思路 官方题解是倒推,这里提供一种正推的做法. 不知道你们是怎么想到倒推的--感觉正推更好想啊QwQ就是不好码 把每一条红边,将其转化为蓝树上的一条路径.为了连这条红边,需要保证这条路径仍然完 ...

  6. 注册InstallShield

    安装InstallShield 下载installshield limitededition版本,这个版本是免费的 注册 安装打开后会给一个网址要求进行注册 其中,国籍是必填项但是下拉菜单中没有内容, ...

  7. 安卓易学,爬坑不易—腾讯老司机的RecyclerView局部刷新爬坑之路

    前言 安卓开发者都知道,RecyclerView比ListView要灵活的多,但不可否认的里面的坑也同样埋了不少人.下面让我们看看腾讯开发工程师用实例讲解自己踩坑时的解决方案和心路历程. 话说有图有真 ...

  8. java怎样将一组对象传入Oracle存储过程

    注:本文来源 <  java怎样将一组对象传入Oracle存储过程  > java怎样将一组对象传入Oracle存储过程 java怎样将一组对象传入Oracle存储过程.须要注意的是jar ...

  9. C# Parallel并发执行相关问题

    1.Parallel并发执行 using System;using System.Collections.Generic;using System.Linq;using System.Text;usi ...

  10. WireShark 实例分析笔记(概念)

    1.嗅探器工作原理(中文版) 安装软件的附带WinPcap(实现从网卡接受数据可视化) 数据嗅探器工作原理,  第一:收集数据(数据包嗅探器从网络线缆上收集原始二进制数据,选定特定网卡设置混杂模式来完 ...