暴力移步 http://www.cnblogs.com/TheRoadToTheGold/p/6673430.html

首先解决本题应用的知识点:

dfs序——将求子树的信息(树形)转化为求一段连续区间信息(线形)

线段树——求区间信息

树上差分——统计答案

lca——拆分路径

树链剖分——求lca

另deep[]表示节点的深度,watch[]表示观察者的出现时间,s表示玩家起点,t表示终点

固定节点的观察者出现的时间固定,说明对这个观察者有贡献的点是有限且固定的

只有满足  观察者出现时间=玩家起点与观察者距离的  玩家才对观察者有贡献

每条路径拆成   起点到lca(向上跑)  和   终点到lca的子节点(向下跑)  的两条路径

对于向上跑的,如果玩家能被观察员i观察到,那么deep[s]-deep[i]=watch[i]   式①

对于向下跑的,就是 deep[s]+deep[i]-2*deep[lca(s,i)]=watch[i]  式②

等号左边是玩家起点与观察者的距离,等号右边是观察者出现时间

向上跑的很显然,向下跑的如何理解?

假设我们知道点a,b到lca(a,b)的距离分别为da,db,那么a,b之间的距离=da+db

但这里的deep不是到lca的距离,是深度,即到根节点的距离+1

deep[s]+deep[i]包含2段信息,1、s到i的距离,   2、lca(s,i)到根节点的距离+1

第2段包含了2次,所以减去

先看向上跑的

玩家路径:玩家起点 到 起点与终点的lca

将式①移项,deep[s]=deep[i]+watch[i]

发现等号右边是定值

也就是说对与观察者i,他所能观察到的向上跑的玩家,是所有的起点=deep[i]+watch[i]的玩家

换句话说,以i为根的子树中,所有深度为deep[i]+watch[i]的玩家都能被i观察到

我们如果搞一个dfs序,i的在a时入栈,在b时出栈,

那么以i为根的子树就可以转化为区间[a,b]

深度咋整?

我们对每个深度建立一颗线段树(动态加点)

那么问题就转化为了  在深度为deep[i]+watch[i]的线段树中,查询区间[a,b]的玩家个数

现在就差玩家个数了

很容易想到在起点处+1

但是还要在起点与终点的lca的父节点处-1

差分惯用思想

用sum[]统计这些1和-1的和

那么问题就转化为了  在深度为deep[i]+watch[i]的线段树中,查询区间[a,b]的sum和

提问:为什么是起点处+1,lca的父节点处-1,可以反过来吗?

不可以。

因为起点的深度深,lca的父节点深度浅,在深度深的节点处+1,以深度深度浅的点为根的子树可以包含这个点

想想序列上的差分,是左端点+1,右端点后面的点-1

因为序列差分与前缀和相联系,前面的点的信息对后面的点会产生影响,所以只需加一个1

这里查询的是子树信息,是这个点深度及以下的信息

对照理解即可

向下跑的同理,只简单说怎么做

玩家路径:lca的子节点到玩家终点

把式②移项 deep[s]-2*deep[lca(s,i)]=watch[i]-deep[i]

在watch[i]-deep[i]深度为deep[s]-2*deep[lca(s,i)]的线段树中,终点处+1,lca处-1

查询时查深度为watch[i]-deep[i]的线段树即可

2个小问题:

1、做完向上跑的后,不要忘了清空线段树

2、向下跑的deep[s]-2*deep[lca(s,i)]可能会产生负数,所以全体后移一定长度,root[]数组开大

我后移了2*n,那么root[]数组要开3倍

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 300401
using namespace std;
int n,m,fa[N],son[N],deep[N],bl[N],sz,id[N],ans[N];
int in[N],out[N],watch[N];
int front[N],nextt[N*],to[N*];
int root[N*],lc[N*],rc[N*],sum[N*],tot,cnt;
struct node
{
int s,t,lca;
}runner[N];
void add(int u,int v)
{
to[++cnt]=v; nextt[cnt]=front[u]; front[u]=cnt;
}
void dfs1(int now)
{
son[now]++;
for(int i=front[now];i;i=nextt[i])
{
if(to[i]==fa[now]) continue;
deep[to[i]]=deep[now]+;
fa[to[i]]=now;
dfs1(to[i]);
son[now]+=son[to[i]];
}
}
void dfs2(int now,int chain)
{
id[now]=++sz;
in[now]=sz;
bl[now]=chain;
int y=;
for(int i=front[now];i;i=nextt[i])
{
if(to[i]==fa[now]) continue;
if(son[to[i]]>son[y]) y=to[i];
}
if(!y)
{
out[now]=sz;
return;
}
dfs2(y,chain);
for(int i=front[now];i;i=nextt[i])
{
if(to[i]==fa[now]||to[i]==y) continue;
dfs2(to[i],to[i]);
}
out[now]=sz;
}
int getlca(int u,int v)
{
while(bl[u]!=bl[v])
{
if(deep[bl[u]]<deep[bl[v]]) swap(u,v);
u=fa[bl[u]];
}
return deep[u]<deep[v] ? u:v;
}
void change(int & now,int l,int r,int pos,int w)
{
if(!pos) return;
if(!now) now=++tot;
sum[now]+=w;
if(l==r) return;
int mid=l+r>>;
if(pos<=mid) change(lc[now],l,mid,pos,w);
else change(rc[now],mid+,r,pos,w);
}
int query(int now,int l,int r,int opl,int opr)
{
if(!now) return ;
if(l==opl&&r==opr) return sum[now];
int mid=l+r>>;
if(opr<=mid) return query(lc[now],l,mid,opl,opr);
else if(opl>mid) return query(rc[now],mid+,r,opl,opr);
else return query(lc[now],l,mid,opl,mid)+query(rc[now],mid+,r,mid+,opr);
}
void clear()
{
tot=;
memset(lc,,sizeof(lc));
memset(rc,,sizeof(rc));
memset(sum,,sizeof(sum));
memset(root,,sizeof(root));
}
int main()
{
/*freopen("runninga.in","r",stdin);
freopen("runninga.out","w",stdout);*/
scanf("%d%d",&n,&m);
int u,v;
for(int i=;i<n;i++)
{
scanf("%d%d",&u,&v);
add(u,v);add(v,u);
}
for(int i=;i<=n;i++) scanf("%d",&watch[i]);
for(int i=;i<=m;i++) scanf("%d%d",&runner[i].s,&runner[i].t);
dfs1();
dfs2(,);
for(int i=;i<=m;i++) runner[i].lca=getlca(runner[i].s,runner[i].t);
int now;
for(int i=;i<=m;i++)
{
now=deep[runner[i].s];
change(root[now],,n,id[runner[i].s],);
change(root[now],,n,id[fa[runner[i].lca]],-);
}
for(int i=;i<=n;i++) ans[i]=query(root[deep[i]+watch[i]],,n,in[i],out[i]);
clear();
for(int i=;i<=m;i++)
{
now=deep[runner[i].s]-deep[runner[i].lca]*+n*;
change(root[now],,n,id[runner[i].t],);
change(root[now],,n,id[runner[i].lca],-);
}
for(int i=;i<=n;i++) ans[i]+=query(root[watch[i]-deep[i]+n*],,n,in[i],out[i]);
for(int i=;i<=n;i++) printf("%d ",ans[i]);
}

NOIP2016 天天爱跑步 正解的更多相关文章

  1. [Noip2016]天天爱跑步 LCA+DFS

    [Noip2016]天天爱跑步 Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要玩家每天按时上线,完成打卡任 ...

  2. [NOIp2016]天天爱跑步 线段树合并

    [NOIp2016]天天爱跑步 LG传送门 作为一道被毒瘤出题人们玩坏了的NOIp经典题,我们先不看毒瘤的"动态爱跑步"和"天天爱仙人掌",回归一下本来的味道. ...

  3. 【LG1600】[NOIP2016]天天爱跑步

    [LG1600][NOIP2016]天天爱跑步 题面 洛谷 题解 考虑一条路径\(S\rightarrow T\)是如何给一个观测点\(x\)造成贡献的, 一种是从\(x\)的子树内出来,另外一种是从 ...

  4. BZOJ4719 [Noip2016]天天爱跑步

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转 ...

  5. bzoj 4719: [Noip2016]天天爱跑步

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

  6. NOIP2016 天天爱跑步 80分暴力

    https://www.luogu.org/problem/show?pid=1600 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养 ...

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

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

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

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

  9. 4719: [Noip2016]天天爱跑步

    Time Limit: 40 Sec Memory Limit: 512 MB Submit: 1986 Solved: 752 [Submit][Status][Discuss] Descripti ...

随机推荐

  1. POJ 1087 A Plug for UNIX (网络流,最大流)

    题面 You are in charge of setting up the press room for the inaugural meeting of the United Nations In ...

  2. [Luogu2073]送花

    题面 题目背景 小明准备给小红送一束花,以表达他对小红的爱意.他在花店看中了一些花,准备用它们包成花束. 题目描述 这些花都很漂亮,每朵花有一个美丽值W,价格为C. 小明一开始有一个空的花束,他不断地 ...

  3. [BZOJ1045] [HAOI2008] 糖果传递 (贪心)

    Description 有n个小朋友坐成一圈,每人有ai个糖果.每人只能给左右两人传递糖果.每人每次传递一个糖果代价为1. Input 第一行一个正整数n<=,表示小朋友的个数.接下来n行,每行 ...

  4. 【learning】多项式乘法&fft

    [吐槽] 以前一直觉得这个东西十分高端完全不会qwq 但是向lyy.yxq.yww.dtz等dalao们学习之后发现这个东西的代码实现其实极其简洁 于是趁着还没有忘记赶紧来写一篇博 (说起来这篇东西的 ...

  5. 空间金字塔池化(Spatial Pyramid Pooling, SPP)原理和代码实现(Pytorch)

    想直接看公式的可跳至第三节 3.公式修正 一.为什么需要SPP 首先需要知道为什么会需要SPP. 我们都知道卷积神经网络(CNN)由卷积层和全连接层组成,其中卷积层对于输入数据的大小并没有要求,唯一对 ...

  6. hive java编写udf函数

    (一)创建JAVA 代码--例子 package hiveOpt; import org.apache.hadoop.hive.ql.exec.UDF;import org.apache.hadoop ...

  7. 《阿里巴巴Android编码规范》阅读纪要(二)

    版权声明:本文出自汪磊的博客,转载请务必注明出处. 本篇继续上一篇<阿里巴巴Android编码规范>阅读纪要(一) ,还是建议各位同学有时间完整阅读一下<阿里巴巴Android编码规 ...

  8. 微信小程序-布局

    flex-direction 传送门 border 传送门 边框 粗细:thin(细线).medium(中粗线)和thick(粗线) 类型:九个确定值:none(无边框线). dotted(由点组成的 ...

  9. 常用JS小知识汇总

    1 上传图片:html代码 <input id="image" type='file' name='myFile' size='15' onchange="show ...

  10. install-scp

    centos6 minilize system will not scp command install: yum -y install openssh-clients and another mac ...