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

题目描述

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

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

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

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

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

输入格式

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

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

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

接下来 mmm 行,每行两个整数 sis_isi​,和 tit_iti​,表示一个玩家的起点和终点。

对于所有的数据,保证 1≤si,ti≤n,0≤wj≤n1\leq s_i,t_i\leq n, 0\leq w_j\leq n1≤si​,ti​≤n,0≤wj​≤n。

输出格式

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


【题解】洛谷1600天天爱跑步

#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int N=6e5+10;
inline int read(){
    int x=0; char c=getchar();
    while(c<'0'||c>'9')c=getchar();
    while('0'<=c&&c<='9'){ x=(x<<3)+(x<<1)+(c^48); c=getchar(); }
    return x;
}
int nxt[N<<1],head[N],go[N<<1],tot;
inline void add(int u,int v){nxt[++tot]=head[u],head[u]=tot,go[tot]=v,nxt[++tot]=head[v],head[v]=tot,go[tot]=u;}
int n,m,w[N],f[N][17];
struct node{
    int x,lca,op;
};
vector<node>a[N];
int dep[N];
void deal(int u,int fa){
    dep[u]=dep[fa]+1;
    for(int i=0;i<16;i++)f[u][i+1]=f[f[u][i]][i];
    for(int i=head[u];i;i=nxt[i]){
        int v=go[i];
        if(v==fa)continue;
        f[v][0]=u;
        deal(v,u);
    }
}
#define _ 10000
inline int LCA(int x,int y){
    if(dep[x]<dep[y])swap(x,y);
    for(int i=16;i>=0;i--)if(dep[f[x][i]]>=dep[y])x=f[x][i];
    if(x==y)return x;
    for(int i=16;i>=0;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
    return f[x][0];
}
int cnt1[N],cnt2[N],ans[N];
vector<int>del1[N],del2[N];
void dfs(int u,int fa){
    int x=cnt1[_+dep[u]+w[u]],y=cnt2[_+w[u]-dep[u]];
    for(int i=head[u];i;i=nxt[i]){
        int v=go[i];
        if(v==fa)continue;
        dfs(v,u);
    }
    for(int i=0;i<a[u].size();i++){
        int x=a[u][i].x,lca=a[u][i].lca;
        if(a[u][i].op){
            cnt1[_+dep[u]]++;
            del1[lca].push_back(dep[u]);
        }
        else {
            cnt2[_+dep[x]-2*dep[lca]]++;
            del2[lca].push_back(dep[x]-2*dep[lca]);
        }
    }
    for(int i=0;i<del1[u].size();i++)cnt1[_+del1[u][i]]--;
    ans[u]=cnt1[_+dep[u]+w[u]]-x+cnt2[_+w[u]-dep[u]]-y;
    for(int i=0;i<del2[u].size();i++)cnt2[_+del2[u][i]]--;
}
signed main(){
    n=read(),m=read();
    for(int i=1;i<n;i++)add(read(),read());
    deal(1,1);
    for(int i=1;i<=n;i++)w[i]=read();
    for(int i=1,x,y,z;i<=m;i++){
        x=read(),y=read();
        z=LCA(x,y);
        a[x].push_back((node){y,z,1});
        a[y].push_back((node){x,z,0});
    }
    dfs(1,0);
    for(int i=1;i<=n;i++)printf("%d ",ans[i]);
    printf("\n");
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/naruto-mzx/p/12150157.html