码了一个下午加一个晚上吧。。。。。。

题目描述:

小c同学认为跑步非常有趣,于是决定制作一款叫做《天天爱跑步》的游戏。《天天爱跑步》是一个养成类游戏,需要玩家每天按时上线,完成打卡任务。

这个游戏的地图可以看作一一棵包含 n个结点和 n-1条边的树, 每条边连接两个结点,且任意两个结点存在一条路径互相可达。树上结点编号为从1到n的连续正整数。

现在有m个玩家,第i个玩家的起点为 Si,终点为 Ti 。每天打卡任务开始时,所有玩家在第0秒同时从自己的起点出发, 以每秒跑一条边的速度, 不间断地沿着最短路径向着自己的终点跑去, 跑到终点后该玩家就算完成了打卡任务。 (由于地图是一棵树, 所以每个人的路径是唯一的)

小c想知道游戏的活跃度, 所以在每个结点上都放置了一个观察员。 在结点jj的观察员会选择在第Wj秒观察玩家, 一个玩家能被这个观察员观察到当且仅当该玩家在第Wj秒也理到达了结点j。 小c想知道每个观察员会观察到多少人?

注意: 我们认为一个玩家到达自己的终点后该玩家就会结束游戏, 他不能等待一 段时间后再被观察员观察到。 即对于把结点j作为终点的玩家: 若他在第Wj秒前到达终点,则在结点j的观察员不能观察到该玩家;若他正好在第Wj秒到达终点,则在结点j的观察员可以观察到这个玩家。

数据范围:

思路分析:

某王 云:任何题目的正解都是由部分分推导出来的,部分分就是在引导你走向正解。

嗯,好,我们开始讲部分分。

25分:

和人一起跳就是,lca O(n)就行,都不带优化的。

20分(s[i]=1):

以根为起点,那么对于点u,显然只有当depth[u]=w[u]时,才有可能有路径能够对它产生贡献。

怎么样的路径才会对它产生贡献呢?——简单啊,t在以u为根的子树中就行了嘛。

那么这个值只要用树形DP搞一搞就行了。

20分(t[i]=1):

以根为终点,对于节点u,只有起点在以u为根的子树中且深度为depth[u]+w[u]的路径才会对点u产生贡献。

我们可以搞一个桶,把起点深度相同的点全部丢进同一个桶bac[depth[s]]。

那么当我们访问到节点u时,一个变量pre记录一下当前bac[depth[u]+w[u]]的值,同时bac[depth[u]]+=tot[u],其中tot[u]表示以u节点为起点的路径数量。

当我们要退出这个点时,ans[u]+=bac[depth[u]+w[u]]-pre。(“类似”差分)

吐槽一下:我刚做这题的时候,同学告诉我这题是差分,误导了我好久。。。。。。

100分(出现辣——正解!!!):

嗯,某王 其实说的很对,特别有道理!——没错,正解就是“综上所述”

把一条链分为两段,s到lca一段(这段是往上走的),lca到t一段(这段是往下的)。

先分类讨论一下:

对于一个节点u,我们将对其产生贡献的路径分为两种:1:自下而上经过它,从而产生贡献。2:自上而下经过它,从而产生贡献。

1、自下而上:

这个和t[i]=1其实类似。

能用这种方式对点u产生贡献的路径需要满足:

1、起点在以u为根的子树中,终点在u以及u的祖先中。

2、depth[s]=depth[u]+w[u]

然后像t[i]=1那样用桶,类差分一下就行了。

更新操作:

bac[depth[u]]+=tot[u]

细节处理:

当我们要退出一个节点u时要枚举所有以u节点为lca的路径,然后bac[depth[s]]--。

为什么呢?——因为条件1嘛!

当u节点退出后,就会进入u的父亲,而这条路径的上半段对于u的父亲与u的兄弟是没有贡献的(因为这段路径的起点(lca)并不在它们自己或是它们的祖先中了)。

2、自上而下:

这个稍微难一点点。

能对节点u产生贡献的路径,起点不一定是u节点的祖先,也有可能是u的兄弟(这个能想象吧,就是先往上走,再折下来的那种)。

但是能对节点u产生贡献的路径,他们的起点与u的距离肯定是w[u]。

所以需要满足:

1、终点在以u为根的子树中,起点不在以u为根的子树中。

2、 depth[s]+depth[u]-2*depth[lca(s,u)]=w[u]

depth[s]-2*depth[lca(s,t)]+depth[u]=w[u]

depth[s]+depth[t]-2*depth[lca(s,t)]+depth[u]-depth[t]=w[u]

len[s,t]-depth[t]=w[u]-depth[u]

这里讲一下为什么lca(s,u)=lca(s,t)吧,因为不管这条路径属于上面两种情况的哪一种,只要满足了条件1,那么depth[lca(s,t)]>=depth[u]对吧,而t又在以u为根的子树中,那么lca肯定不会变啊。

同样的,用桶类差分即可。

但是此时类差分的时候要注意:把s丢进bac[len[s,t]-depth[t]]中,询问时要找的桶是bac[w[u]-depth[u]](上面应该讲的很清楚了吧)。

更新操作:

退出一个节点时,枚举所有以u为终点的路径,然后bac[depth[len[s,t]-depth[t]]]++。

细节处理:

退出一个节点时,枚举所有以u为lca的路径,然后bac[depth[len[s,t]-depth[t]]]--。(这个和上面差不多就不讲了)

代码实现:

var
head:array[1..4,0..300000]of longint;
next,len,vet:array[1..2000000]of longint;
vis:array[0..300000]of boolean;
depth,ans,sum,w:array[0..300000]of longint;
bac:array[-300000..300000]of longint;
f:array[0..300000,0..20]of longint;
i,n,m,x,y,s,t,z,tot,l:longint;
procedure add(k,x,y,z:longint);
begin
inc(tot);
next[tot]:=head[k,x];
vet[tot]:=y;
head[k,x]:=tot;
len[tot]:=z;
end;
procedure dfs(u,dep:longint);
var
i,v:longint;
begin
depth[u]:=dep; vis[u]:=true;
for i:=1 to 20 do
f[u,i]:=f[f[u,i-1],i-1];
i:=head[1,u];
while i<>0 do
begin
v:=vet[i];
if not vis[v] then
begin f[v,0]:=u; dfs(v,dep+1); end;
i:=next[i];
end;
end;
function lca(a,b:longint):longint;
var
i,t:longint;
begin
if depth[a]>depth[b] then begin t:=a; a:=b; b:=t; end;
for i:=20 downto 0 do
if depth[f[b,i]]>=depth[a] then b:=f[b,i];
if a=b then exit(a);
for i:=20 downto 0 do
if f[a,i]<>f[b,i] then
begin a:=f[a,i]; b:=f[b,i]; end;
exit(f[a,0]);
end;
procedure up(u,father:longint);
var
i,v,s,pre:longint;
begin
pre:=bac[w[u]+depth[u]];
i:=head[1,u];
while i<>0 do
begin
v:=vet[i];
if v<>father then up(v,u);
i:=next[i];
end;
bac[depth[u]]:=bac[depth[u]]+sum[u];
ans[u]:=ans[u]+bac[w[u]+depth[u]]-pre;
i:=head[2,u];
while i<>0 do
begin s:=vet[i]; dec(bac[depth[s]]); i:=next[i]; end;
end;
procedure down(u,father:longint);
var
i,pre,s,t,v:longint;
begin
pre:=bac[w[u]-depth[u]];
i:=head[1,u];
while i<>0 do
begin
v:=vet[i];
if v<>father then down(v,u);
i:=next[i];
end;
i:=head[4,u];
while i<>0 do
begin t:=vet[i]; inc(bac[len[i]-depth[t]]); i:=next[i]; end;
ans[u]:=ans[u]+bac[w[u]-depth[u]]-pre;
i:=head[3,u];
while i<>0 do
begin t:=vet[i]; dec(bac[len[i]-depth[t]]); i:=next[i]; end;
end;
begin
read(n,m);
for i:=1 to n-1 do
begin
read(x,y);
add(1,x,y,0); add(1,y,x,0);
end;
dfs(1,1);
for i:=1 to n do read(w[i]);
for i:=1 to m do
begin
read(s,t); z:=lca(s,t); inc(sum[s]); l:=depth[s]+depth[t]-2*depth[z];
if depth[s]-depth[z]=w[z] then dec(ans[z]);
add(2,z,s,0); add(3,z,t,l); add(4,t,t,l);
end;
up(1,0);
fillchar(bac,sizeof(bac),0);
down(1,0);
for i:=1 to n do
write(ans[i],' ');
end. //感觉guide不好用。。。。。。

NOIP提高组2016 D1T2 【天天爱跑步】的更多相关文章

  1. 题解——洛谷P2827 NOIP提高组 2016 蚯蚓

    队列模拟 详细题解待填坑 #include <cstdio> #include <algorithm> #include <queue> #include < ...

  2. NOIP提高组2016总结

    前言 大翻车! 300--: day1 8:30~9:00, 照常看题,思考. 9:00~9:15, 搞定第一题,很水. 9:15~9:45, 思考第二题,我考虑用分深度来处理,想出个个玄学暴力,但刚 ...

  3. NOIP提高组2016 D2T3 【愤怒的小鸟】

    貌似还没有写过状压DP的题目,嗯,刚好今天考了,就拿出来写一写吧. 题目大意: 额,比较懒,这次就不写了... 思路分析: 先教大家一种判断题目是不是状压DP的方法吧. 很简单,那就是--看数据范围! ...

  4. NOIP提高组初赛难题总结

    NOIP提高组初赛难题总结 注:笔者开始写本文章时noip初赛新题型还未公布,故会含有一些比较老的内容,敬请谅解. 约定: 若无特殊说明,本文中未知数均为整数 [表达式] 表示:在表达式成立时它的值为 ...

  5. NOIP提高组2004 合并果子题解

    NOIP提高组2004 合并果子题解 描述:在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆.多多决定把所有的果子合成一堆. 每一次合并,多多可以把两堆果子合并到一起,消 ...

  6. 计蒜客 NOIP 提高组模拟竞赛第一试 补记

    计蒜客 NOIP 提高组模拟竞赛第一试 补记 A. 广场车神 题目大意: 一个\(n\times m(n,m\le2000)\)的网格,初始时位于左下角的\((1,1)\)处,终点在右上角的\((n, ...

  7. 1043 方格取数 2000 noip 提高组

    1043 方格取数  2000 noip 提高组 题目描述 Description 设有N*N的方格图(N<=10,我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0.如下图所示(见样 ...

  8. [NOIP提高组2018]货币系统

    [TOC] 题目名称:货币系统 来源:2018年NOIP提高组 链接 博客链接 CSDN 洛谷博客 洛谷题解 题目链接 LibreOJ(2951) 洛谷(P5020) 大视野在线评测(1425) 题目 ...

  9. 津津的储蓄计划 NOIp提高组2004

    这个题目当年困扰了我许久,现在来反思一下 本文为博客园ShyButHandsome的原创作品,转载请注明出处 右边有目录,方便快速浏览 题目描述 津津的零花钱一直都是自己管理.每个月的月初妈妈给津津\ ...

随机推荐

  1. Google Code Jam 2020 Round1B Join the Ranks

    题意 给你一个形如\(1,2,\cdots,R,1,2,\cdots,R,1\cdots\)的序列,共重复\(C\)次.你每次可以选择一个区间\([L,R]\)将其平移到序列首部,最终使得序列具有\( ...

  2. 02 axios

    request.js import axios from 'axios' const config = require('@/config') const instance = axios.creat ...

  3. Python之 最全 Conda、pip 管理环境和安装包、更换源、解决HttpError等一些列问题

    在Anaconda中conda可以理解为一个工具,也是一个可执行命令,其核心功能是环境管理与包管理.所以对虚拟环境进行创建.删除等操作需要使用conda命令. conda install 和 pip ...

  4. SQL分词器1.10版

    处理SQL及分词效果: select * from ( select rownum as rn,tb1.stuid,tb1.summary from ( select stuid,sum(score) ...

  5. Html中让输入框input和紧接在后的按钮button在垂直方向上对齐

    <table border="0px" width="360px"> <tr><td colspan="10" ...

  6. HTTP 协议类

    HTTP 协议的主要特点 简单快速:每个资源的URL是固定的 灵活:在每个 http 协议中都有一个头部分有一个数据类型,通过一个 http 协议就可以完成不同数据类型的传输 无连接:连接一次就好断掉 ...

  7. MySQL 8 安装教程(个人版)+创建用户

    Mysql 8的安装教程 解压到指定目录如:D:\WinInstall\mysql-8.0.19-winx64这时候你需要在根目录下创建两个文件,分别是data文件夹和my.ini文件,然后使用编辑器 ...

  8. mysql数据库常见问题修改(待补充)

    1.修改mysql最大连接数的方法:临时修改:1.使用命令show variables 来查看当前最大连接数 show variables like '%max_connections%'; 使用命令 ...

  9. Hadoop入门学习整理(一)

    今天是2020年4月8日,是一个平凡而又特殊的日子,武汉在经历了77天的封城之后,于今日0点正式解封.从1月14日放寒假离开武汉,到今天已近3个月,学校的花开了又谢了.随着疫情好转,春回大地,万物复苏 ...

  10. C#开发PACS医学影像处理系统(十四):处理Dicom影像窗宽窗位

    概念解释(网络资料): 窗宽: 窗宽指CT图像所显示的CT 值范围.在此CT值范围内的组织结构按其密度高低从白到黑分为16 个灰阶以供观察对比.例如,窗宽选定为100 Hu ,则人眼可分辨的CT值为1 ...