NOIP2016提高组Day1T2 天天爱跑步 树链剖分 LCA 倍增 差分
原文链接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 倍增 差分的更多相关文章
- BZOJ4719[NOIP2016提高组Day1T2] 天天爱跑步
		
#261. [NOIP2016]天天爱跑步 描述 提交 自定义测试 小C同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家 ...
 - NOIP2015 运输计划 - 二分 + 树链剖分 / (倍增 + 差分)
		
BZOJ CodeVS Uoj 题目大意: 给一个n个点的边带权树,给定m条链,你可以选择树中的任意一条边,将它置为0,使得最长的链长最短. 题目分析: 最小化最大值,二分. 二分最短长度mid,将图 ...
 - NOIP2016提高组D1T2 天天爱跑步
		
n<=300000个点的树,每个点有个人于第Ti秒观测,有m<=300000个人于时间0开始从Sj跑到Tj,速度1个点每秒,输出每个点上的人观察到的跑步的人的数量. 前25分:直接模拟每条 ...
 - BZOJ 4719 [Noip2016]天天爱跑步 ——树链剖分
		
一直以为自己当时是TLE了,但是再看发现居然WA? 然后把数组扩大一倍,就A掉了.QaQ 没什么好说的.一段路径分成两段考虑,上升的一段深度+时间是定值,下降的一段深度-时间是定值,然后打标记统计即可 ...
 - 树链剖分与倍增求LCA
		
树链剖分与倍增求\(LCA\) 首先我要吐槽机房的辣基供电情况,我之前写了一上午,马上就要完成的时候突然停电,然后\(GG\)成了送链剖分 其次,我没歧视\(tarjan LCA\) 1.倍增求\(L ...
 - 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 ...
 - 【BZOJ】2819: Nim(树链剖分 / lca+dfs序+树状数组)
		
题目 传送门:QWQ 分析 先敲了个树链剖分,发现无法AC(其实是自己弱,懒得debug.手写栈) 然后去学了学正解 核心挺好理解的,$ query(a) $是$ a $到根的异或和. 答案就是$ l ...
 - POJ - 2763 Housewife Wind (树链剖分/ LCA+RMQ+树状数组)
		
题意:有一棵树,每条边给定初始权值.一个人从s点出发.支持两种操作:修改一条边的权值:求从当前位置到点u的最短路径. 分析:就是在边可以修改的情况下求树上最短路.如果不带修改的话,用RMQ预处理LCA ...
 - BZOJ 3083 遥远的国度(树链剖分+LCA)
		
Description 描述zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要z ...
 
随机推荐
- [正则表达式]匹配Unicode
			
一.PHP[PCRE]之Unicode PCRE支持的16进制字符编码转义符有 \x00-\xFF,或\x{num},num为任意位16进制数 但并不支持\u0000-\uFFFF这的形式 PCRE运 ...
 - highcharts之柱状图
			
<div class="row"> <div class="col-md-12"> <div id="container ...
 - cocos2d内存管理,类的生命周期
			
下面资料来自<Cocos2d-x之Lua核心编程>
 - winform的水印TextBox
			
public partial class WaterTextBox : TextBox { private readonly Label lblwaterText = new Label(); pub ...
 - IntellJ IDEA下写JUnit
			
安装配置JUnit File->Settings->Plugins->Browse Repositories->在右侧搜索框输入"junit"-> ...
 - 用VS制作的windows服务安装包 安装完后如何让服务自动启动
			
vs 服务做成安装包,如何安装以后启动服务,只要在类名为projectinstaller的类中重写commit事件即可 public override void Commit(IDic ...
 - vue.js的计算机属性学习
			
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
 - SpringCloud服务提供者
			
服务提供者就是提供一个服务暴露出来给别人调用,在springcloud中需要注册服务到服务中心 搭建服务提供者项目(ProduceDemo) 1.创建pom.xml <project xmlns ...
 - SpringBoot图片上传(一)
			
简单描述:点击上传文件的图标,上传文件,上传成功后,图标编程上传的图片. 吐槽:文件上传下载这种东西,总是感觉莫名的虚-_-|| 也不知道是造了什么孽,(其实就是IO File这一块的知识了解的不太 ...
 - 《剑指offer》 反转链表
			
本题来自<剑指offer> 反转链表 题目: 输入一个链表,反转链表后,输出新链表的表头. 思路: 需要三个变量,来保存当前节点的,前面节点和反转后的节点. C++ Code: /* st ...