「NOIP2016」天天爱跑步

版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/qq_35950004/article/details/83820636

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

这个游戏的地图可以看作一棵包含 spanclass="katex">n n n 个结点和 n−1 n - 1 n1 条边的树,每条边连接两个结点,且任意两个结点存在一条路径互相可达。树上结点编号为从 1 1 1n 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 12n=m=991 n = m = 991 n=m=991,所有人的起点等于自己的终点,即 Si=Ti S_i = T_i Si=Ti
测试点 3∼4 3 \sim 4 34n=m=992 n = m = 992 n=m=992Wj=0 W_j = 0 Wj=0
测试点 5 5 5n=m=993 n = m = 993 n=m=993
测试点 6∼8 6 \sim 8 68n=m=99994 n = m = 99994 n=m=99994,树退化成一条链,对于 1≤i<n 1 \leq i < n 1i<ni i ii+1 i + 1 i+1 有边;
测试点 9∼12 9 \sim 12 912n=m=99995 n = m = 99995 n=m=99995Si=1 S_i = 1 Si=1
测试点 13∼16 13 \sim 16 1316n=m=99996 n = m = 99996 n=m=99996Ti=1 T_i = 1 Ti=1
测试点 17∼19 17 \sim 19 1719n=m=99997 n = m = 99997 n=m=99997
测试点 20 20 20n=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]);
}

猜你喜欢

转载自blog.csdn.net/qq_35950004/article/details/83820636