BZOJ 4719--天天爱跑步(LCA&差分)

4719: [Noip2016]天天爱跑步

Time Limit: 40 Sec  Memory Limit: 512 MB
Submit: 1464  Solved: 490
[Submit][Status][Discuss]

Description

小c同学认为跑步非常有趣,于是决定制作一款叫做《天天爱跑步》的游戏。?天天爱跑步?是一个养成类游戏,需要

玩家每天按时上线,完成打卡任务。这个游戏的地图可以看作一一棵包含 N个结点和N-1 条边的树, 每条边连接两

个结点,且任意两个结点存在一条路径互相可达。树上结点编号为从1到N的连续正整数。现在有个玩家,第个玩家的

起点为Si ,终点为Ti  。每天打卡任务开始时,所有玩家在第0秒同时从自己的起点出发, 以每秒跑一条边的速度,

不间断地沿着最短路径向着自己的终点跑去, 跑到终点后该玩家就算完成了打卡任务。 (由于地图是一棵树, 所以

每个人的路径是唯一的)小C想知道游戏的活跃度, 所以在每个结点上都放置了一个观察员。 在结点的观察员会选

择在第Wj秒观察玩家, 一个玩家能被这个观察员观察到当且仅当该玩家在第Wj秒也理到达了结点J  。 小C想知道

每个观察员会观察到多少人?注意: 我们认为一个玩家到达自己的终点后该玩家就会结束游戏, 他不能等待一 段时

间后再被观察员观察到。 即对于把结点J作为终点的玩家: 若他在第Wj秒重到达终点,则在结点J的观察员不能观察

到该玩家;若他正好在第Wj秒到达终点,则在结点的观察员可以观察到这个玩家。

Input

第一行有两个整数N和M 。其中N代表树的结点数量, 同时也是观察员的数量, M代表玩家的数量。

接下来n-1 行每行两个整数U和V ,表示结点U 到结点V 有一条边。

接下来一行N 个整数,其中第个整数为Wj , 表示结点出现观察员的时间。

接下来 M行,每行两个整数Si和Ti,表示一个玩家的起点和终点。

对于所有的数据,保证 。

1<=Si,Ti<=N,0<=Wj<=N

Output

输出1行N 个整数,第个整数表示结点的观察员可以观察到多少人。

Sample Input

6 3
2 3
1 2
1 4
4 5
4 6
0 2 5 1 2 3
1 5
1 3
2 6

Sample Output

2 0 0 1 1 1

HINT

对于1号点,W1=0,故只有起点为1号点的玩家才会被观察到,所以玩家1和玩家2被观察到,共2人被观察到。

对于2号点,没有玩家在第2秒时在此结点,共0人被观察到。

对于3号点,没有玩家在第5秒时在此结点,共0人被观察到。

对于4号点,玩家1被观察到,共1人被观察到。

对于5号点,玩家1被观察到,共1人被观察到。

对于6号点,玩家3被观察到,共1人被观察到

题目链接:

    http://www.lydsy.com/JudgeOnline/problem.php?id=1096

Solution

    刚开始学OI的时候就看过这道题。。。当时是贴代码过的。。。。

    记得好像是用树链剖分。。不记得了。。反正很长。。。

    现在快要noip了。。。把往年的题目拿出来看一下,算是临近noip的梳理吧。。。。。

    好多废话

    进入正题。。。。。

    首先每个人都要走最短路径。。。马上想到LCA。。。不然还能有什么。。。

    每个人分别统计显然是不行的,不过似乎可以根据特殊情况水很多分。。

    于是想到差分。。

    假设第 i 个人的起点为 Si ,终点为 Ti 。。LCA ( Si ,Ti ) =  rt

    每条线段长度都是 1 ,故路径长度与深度有关。。。

    于是路径就可以分成两部分:Si -> rt  和 rt ->Ti

    两条路径分开统计。。。

    在向上的路径中,比如一个起点 Si ,深度为 dep [ Si ] ,

    那么可以在遍历到Si的时候 U [ dep [ Si ] ] ++;

    然后在到达 rt 的父亲的时候 U [ dep [ Si ] ] --;  (U [ i ]表示某一方向路径的总值)

    向下的路径用一样的方法。。。但这样rt 的统计会有重复。。

    所以两次统计中要有一次在 rt 的时候就 U [ dep [ Si ] ] - - ;

    这样就可以了,虽然分析很长但代码不是很长。。。。

    注意在BZOJ上提交不能有末尾空格。。。害我PE了一发。。。

代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#define N 400000
using namespace std;
inline int Read(){
    int x=0,f=1;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x*f;
}
int n,m,cnt=0;
int fa[N][22];
int hed[N],w[N],dep[N],ans[N],U[N],D[N<<1];
struct edge{
    int r,nxt;
}e[N<<1];
struct node{
    int u,w;
};
vectore1[N],e2[N<<1];
void insert(int u,int v){
    e[++cnt]=(edge){v,hed[u]};hed[u]=cnt;
    e[++cnt]=(edge){u,hed[v]};hed[v]=cnt;
}
void dfs1(int x,int F){
    for(int i=1;(1<<i)<=dep[x];i++)
        fa[x][i]=fa[fa[x][i-1]][i-1];
    for(int i=hed[x];i;i=e[i].nxt)
        if(e[i].r!=F){
            dep[e[i].r]=dep[x]+1;
            fa[e[i].r][0]=x;
            dfs1(e[i].r,x);
        }
}
int lca(int u,int v){
    if(dep[u]<dep[v])swap(u,v);
    int d=dep[u]-dep[v];
    for(int i=0;(1<<i)<=d;i++)
        if((1<<i)&d)
            u=fa[u][i];
    if(u==v)return u;
    for(int i=20;i>=0;i--){
        if((1<<i)>dep[u] || fa[u][i]==fa[v][i])continue;
        u=fa[u][i];v=fa[v][i];
    }
    return fa[u][0];
}
void dfs2(int x,int F){
    ans[x]-=U[w[x]+dep[x]];
    ans[x]-=D[w[x]-dep[x]+n];
    for(int i=0;i<e1[x].size();i++)
        U[e1[x][i].u]+=e1[x][i].w;
    for(int i=0;i<e2[x].size();i++)
        D[e2[x][i].u+n]+=e2[x][i].w;
    for(int i=hed[x];i;i=e[i].nxt)
        if(e[i].r!=F)
            dfs2(e[i].r,x);
    ans[x]+=U[w[x]+dep[x]]+D[w[x]-dep[x]+n];
}
int main(){
    int u,v,rt;
    n=Read();m=Read();
    for(int i=1;i<n;i++){
        u=Read();v=Read();
        insert(u,v);
    }
    for(int i=1;i<=n;i++)
        w[i]=Read();
    dfs1(1,0);
    for(int i=1;i<=m;i++){
        u=Read();v=Read();
        rt=lca(u,v);
        e1[u].push_back((node){dep[u],1});
        e1[rt].push_back((node){dep[u],-1});
        e2[v].push_back((node){dep[u]-(dep[rt]<<1),1});
        e2[fa[rt][0]].push_back((node){dep[u]-(dep[rt]<<1),-1});
    }
    dfs2(1,0);
    for(int i=1;i<n;i++)
        printf("%d ",ans[i]);
    printf("%d",ans[n]);
    return 0;
}

  

  

This passage is made by Iscream-2001.

时间: 2024-10-22 16:50:12

BZOJ 4719--天天爱跑步(LCA&差分)的相关文章

Luogu P1600 天天爱跑步 树上差分

Luogu P1600 天天爱跑步 ### 树上差分 题目链接 树上问题 没看出怎么差分 被观察到的条件有两个 lca前一半(包括lca) \(d[S_i]-d[x]=w[x]\) \(d[i]\)表示节点深度 lca后一半 \(d[S_i]+d[x]-2*d[lca(S_i,T_i)]=w[x]\) 但是具体怎么实现这个公式?? 实现 \(d[S_i]=w[x]+d[x]\) 可以转化为线段树合并模型 在\(S_i\)到\(lca\)的路径上增加\(d[S_i]\)的价值 最后求出各点的\(w

luogu P1600 天天爱跑步 |树上差分+LCA

题目描述 小c 同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 nnn 个结点和 n?1n-1n?1 条边的树,每条边连接两个结点,且任意两个结点存在一条路径互相可达.树上结点编号为从 111 到 nnn 的连续正整数. 现在有 mmm 个玩家,第 iii 个玩家的起点为 sis_isi?,终点为 tit_iti?.每天打卡任务开始时,所有玩家在第 000 秒同时

[luogu]P1600 天天爱跑步[LCA]

[luogu]P1600 [NOIP 2016]天天爱跑步 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含n个结点和n−1条边的树, 每条边连接两个结点,且任意两个结点存在一条路径互相可达.树上结点编号为从1到n的连续正整数. 现在有m个玩家,第i个玩家的起点为Si?,终点为Ti? .每天打卡任务开始时,所有玩家在第0秒同时从自己的起点出发, 以每秒跑一条边的速

bzoj4719: [Noip2016]天天爱跑步 树上差分

Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要 玩家每天按时上线,完成打卡任务.这个游戏的地图可以看作一一棵包含 N个结点和N-1 条边的树, 每条边连接两 个结点,且任意两个结点存在一条路径互相可达.树上结点编号为从1到N的连续正整数.现在有个玩家,第个玩家的 起点为Si ,终点为Ti .每天打卡任务开始时,所有玩家在第0秒同时从自己的起点出发, 以每秒跑一条边的速度, 不间断地沿着最短路径向着自己的终点跑去,

NOIP2016Day1T2天天爱跑步(LCA+桶)

据说是今年NOIP最难一题了...我还记得当时满怀期待心情点开Day1的题发现T2就不会了于是怀疑人生良久... 啊好像很多大爷都是用线段树合并写的,我怎么什么数据结构都不会啊呜呜呜... 题目大意就不说了QWQ 网上的O(n)说法说得好简略啊,我理解了好久...可能是我太弱了QAQ这方面的题做得也少 首先我们可以随手推出某个点i可以观测到一个从x跑到y的玩家的话,肯定有d[i]+w[i]=d[x]或者d[i]-w[i]=d[y]-dis[dis为x到y的距离 所以肯定要先求LCA辣,自从转了C

cogs2557 天天爱跑步 LCA

从去年$11$月填到现在的超级天坑--链接:http://cogs.pro/cogs/problem/problem.php?pid=2557 题意--给出一棵树,上面有一堆链,求出每个节点在指定的时刻有几条链恰好到达-- 联赛超纲的开始-- 详细叙述一下从去年十一月到现在的心路历程-- $2016.11$现场:卧槽这题一脸不可做啊-- $2016.12$:这个题出错地方了吧-- $2017.1$:什么玩意--好像是图上的吧-- $2017.2$(此时刚刚学习树):我好像会点了--(会什么?)如

bzoj 4719: [Noip2016]天天爱跑步

Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要 玩家每天按时上线,完成打卡任务.这个游戏的地图可以看作一一棵包含 N个结点和N-1 条边的树, 每条边连接两 个结点,且任意两个结点存在一条路径互相可达.树上结点编号为从1到N的连续正整数.现在有个玩家,第个玩家的 起点为Si ,终点为Ti  .每天打卡任务开始时,所有玩家在第0秒同时从自己的起点出发, 以每秒跑一条边的速度, 不间断地沿着最短路径向着自己的终点跑去

【NOIP2016】天天爱跑步(树上差分)

题意: 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要 玩家每天按时上线,完成打卡任务.这个游戏的地图可以看作一一棵包含 N个结点和N-1 条边的树, 每条边连接两 个结点,且任意两个结点存在一条路径互相可达.树上结点编号为从1到N的连续正整数.现在有个玩家,第个玩家的 起点为Si ,终点为Ti  .每天打卡任务开始时,所有玩家在第0秒同时从自己的起点出发, 以每秒跑一条边的速度, 不间断地沿着最短路径向着自己的终点跑去, 跑到终点后该

LCA+线段树 NOIP2016 天天爱跑步

天天爱跑步 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 nnn个结点和 n?1n-1n?1条边的树, 每条边连接两个结点,且任意两个结点存在一条路径互相可达.树上结点编号为从111到nnn的连续正整数. 现在有mmm个玩家,第iii个玩家的起点为 SiS_iS?i??,终点为 TiT_iT?i?? .每天打卡任务开始时,所有玩家在第000秒同时从自己的起点出