小 C 同学认为跑步非常有趣,于是决定制作一款叫做《天天爱跑步》的游戏。《天天爱跑步》是一个养成类游戏,需要玩家每天按时上线,完成打卡任务。
这个游戏的地图可以看作一棵包含 spanclass="katex">n n n 个结点和 n−1 n - 1 n−1 条边的树,每条边连接两个结点,且任意两个结点存在一条路径互相可达。树上结点编号为从 1 1 1 到 n n n 的连续正整数。
现在有 m m m 个玩家,第 i i i 个玩家的起点为 Si S_i Si,终点为 Ti T_i Ti。每天打卡任务开始时,所有玩家在第 0 0 0 秒同时从自己的起点出发,以每秒跑一条边的速度,不间断地沿着最短路径向着自己的终点跑去,跑到终点后该玩家就算完成了打卡任务。(由于地图是一棵树,所以每个人的路径是唯一的)
小 C 想知道游戏的活跃度,所以在每个结点上都放置了一个观察员。在结点 j j j 的观察员会选择在第 Wj W_j Wj 秒观察玩家,一个玩家能被这个观察员观察到当且仅当该玩家在第 Wj W_j Wj 秒也正好到达了结点 j j j。小 C 想知道每个观察员会观察到多少人?
注意:我们认为一个玩家到达自己的终点后该玩家就会结束游戏,他不能等待一段时间后再被观察员观察到。即对于把结点 j j j 作为终点的玩家:若他在第 Wj W_j Wj 秒前到达终点,则在结点 j j j 的观察员不能观察到该玩家;若他正好在第 Wj W_j Wj 秒到达终点,则在结点 j j j 的观察员可以观察到这个玩家。
测试点 1∼2 1 \sim 2 1∼2:n=m=991 n = m = 991 n=m=991,所有人的起点等于自己的终点,即 Si=Ti S_i = T_i Si=Ti;
测试点 3∼4 3 \sim 4 3∼4:n=m=992 n = m = 992 n=m=992,Wj=0 W_j = 0 Wj=0;
测试点 5 5 5:n=m=993 n = m = 993 n=m=993;
测试点 6∼8 6 \sim 8 6∼8:n=m=99994 n = m = 99994 n=m=99994,树退化成一条链,对于 1≤i<n 1 \leq i < n 1≤i<n,i i i 与 i+1 i + 1 i+1 有边;
测试点 9∼12 9 \sim 12 9∼12:n=m=99995 n = m = 99995 n=m=99995,Si=1 S_i = 1 Si=1;
测试点 13∼16 13 \sim 16 13∼16:n=m=99996 n = m = 99996 n=m=99996,Ti=1 T_i = 1 Ti=1;
测试点 17∼19 17 \sim 19 17∼19:n=m=99997 n = m = 99997 n=m=99997;
测试点 20 20 20:n=m=299998 n = m = 299998 n=m=299998。
这个最强的是这个去重方式,简单暴力而又不好想。
#include<bits/stdc++.h>
#define maxn 300005
using namespace std;
char cb[1<<15],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,stdin),cs==ct)?0:*cs++)
inline void read(int &res){ char ch;for(;!isdigit(ch=getc()););for(res=ch-'0';isdigit(ch=getc());res=ch-'0'+res*10); }
int n,m;
int info[maxn],Prev[maxn<<1],to[maxn<<1],cnt_e,w[maxn];
inline void Node(int u,int v){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v; }
int fa[maxn],siz[maxn],son[maxn],tp[maxn],dep[maxn];
void dfs1(int now,int ff)
{
dep[now] = dep[fa[now] = ff] + 1;
siz[now] = 1, son[now] = -1;
for(int i=info[now];i;i=Prev[i])
if(to[i]!=ff)
{
dfs1(to[i],now);
siz[now]+=siz[to[i]];
if(son[now]==-1 || siz[son[now]] < siz[to[i]]) son[now] = to[i];
}
}
void dfs2(int now,int ff)
{
if(son[now]!=-1) tp[son[now]] = tp[now] , dfs2(son[now],now);
for(int i=info[now];i;i=Prev[i])
if(to[i]!=ff && to[i]!=son[now])
tp[to[i]]=to[i],dfs2(to[i],now);
}
inline int Lca(int u,int v)
{
for(;tp[u]!=tp[v];)
{
if(dep[tp[u]] > dep[tp[v]]) swap(u,v);
v = fa[tp[v]];
}
return dep[u] > dep[v] ? v : u;
}
vector<int>add[2][maxn],del[2][maxn];
int ans[maxn],cnt[2][maxn*2];
void solve(int now,int ff)
{
ans[now] = -cnt[0][dep[now]+w[now]+maxn] - cnt[1][dep[now]-w[now]+maxn];
for(int i=info[now];i;i=Prev[i])
if(to[i]!=ff) solve(to[i],now);
for(int i=0,siz=add[0][now].size();i<siz;i++) cnt[0][add[0][now][i]+maxn]++;
for(int i=0,siz=add[1][now].size();i<siz;i++) cnt[1][add[1][now][i]+maxn]++;
for(int i=0,siz=del[0][now].size();i<siz;i++) cnt[0][del[0][now][i]+maxn]--;
ans[now] += cnt[0][dep[now]+w[now]+maxn] + cnt[1][dep[now]-w[now]+maxn];
for(int i=0,siz=del[1][now].size();i<siz;i++) cnt[1][del[1][now][i]+maxn]--;
}
int main()
{
read(n),read(m);
for(int i=1,u,v;i<n;i++)read(u),read(v),Node(u,v),Node(v,u);
dfs1(1,0),tp[1]=1,dfs2(1,0);
for(int i=1;i<=n;i++) read(w[i]);
for(int i=1,s,t;i<=m;i++)
{
read(s),read(t);
int lca = Lca(s,t);
add[0][s].push_back(dep[s]),del[0][lca].push_back(dep[s]);
add[1][t].push_back(dep[t]-(dep[t]+dep[s]-2*dep[lca])),del[1][lca].push_back(dep[t]-(dep[t]+dep[s]-2*dep[lca]));
}
solve(1,0);
for(int i=1;i<n;i++) printf("%d ",ans[i]);
printf("%d\n",ans[n]);
}