UOJ #261. 【NOIP2016】天天爱跑步

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

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

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

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

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

输入格式

从标准输入读入数据。

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

接下来 n1 行每行两个整数 u 和 v,表示结点 u 到结点 v 有一条边。

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

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

对于所有的数据,保证 1Si,Tin0Wjn

输出格式

输出到标准输出。

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

样例一

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

output

2 0 0 1 1 1

explanation

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

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

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

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

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

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

样例二

input

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

output

1 2 1 0 1

限制与约定

每个测试点的数据规模及特点如下表所示。提示:数据范围的个位上的数字可以帮助判断是哪一种数据类型。

测试点编号n
m约定
1 =991 =991 所有人的起点等于自己的终点,即 Si=Ti
2
3 =992 =992 Wj=0
4
5 =993 =993
6 =99994 =99994 树退化成一条链,其中 1 与 2 有边,2 与 3 有边,…,n1 与 n 有边
7
8
9 =99995 =99995 所有的 Si=1
10
11
12
13 =99996 =99996 所有的 Ti=1
14
15
16
17 =99997 =99997
18
19
20 =299998 =299998

时间限制:2s

空间限制:512MB

下载

样例数据下载

题目连接:http://uoj.ac/problem/261

解题报告:

从一开始自己YY玄学做法(在线处理,复杂度O(kmlogn),k特别玄学,期望值为4~5,可能会退化成n),到卡常数,到fread()和动态开空间(吐血).

最后还是认认真真看题解,写正解(离线处理,复杂度O(mlogn+n)).

树上差分+桶维护.

先将一条路径(s,t)拆成向上(s,lca)和向下(lca,t)的两条路径,

对于向上路径,路径的点x满足dep[x]+w[x]=dep[s],则可以被观察到,在s点把dep[s]放入对应桶中,lca处取出.

同理对于向下的路径,在t点把2*dep[l]-dep[s]放入桶中,lca处取出.

dfs统计差分和.

玄学做法

#include<cstdio>
#include<iostream>
#include<vector>
#include<algorithm>
#include<cmath>
#define BIG 600005
#define ll long long
#define FOR(i,s,t) for(register int i=s;i<=t;++i)
using namespace std;
const int N=BIG>>1;
int nxt[BIG],to[BIG],las[N],w[N],ans[N],
	sz[N],dep[N],f[N],top[N],xu[BIG],sign[BIG];
vector<int>v1[BIG],v2[BIG];
int n,m,x,y,dfn,l,t,need,tot;
inline void read(int &x){
	char c;
	while(c=getchar(),c>'9'||c<'0');
	x=c-48;
	while(c=getchar(),c>='0'&&c<='9')x=(x<<1)+(x<<3)+c-48;
	return ;
}
inline void add(int x,int y){
	nxt[++tot]=las[x];
	las[x]=tot;
	to[tot]=y;
	return;
}
inline void dfs1(int now){
	sz[now]=1;
	for(register int e=las[now];e;e=nxt[e])
		if(!dep[to[e]]){
			dep[to[e]]=dep[now]+1;
			f[to[e]]=now;
			dfs1(to[e]);
			sz[now]+=sz[to[e]];
		}
	return;
}
inline void dfs2(int now,int chain){
	top[now]=chain;
	xu[now]=++dfn;
	register int i=0;
	for(register int e=las[now];e;e=nxt[e])
		if(sz[to[e]]>sz[i]&&to[e]!=f[now])
			i=to[e];
	if(!i)
		return;
	dfs2(i,chain);
	for(register int e=las[now];e;e=nxt[e])
		if(to[e]!=f[now]&&to[e]!=i)
			dfs2(to[e],to[e]);
	return;
} 
inline int lca(int x,int y){
	for(;top[x]!=top[y];dep[top[x]]>dep[top[y]]?x=f[top[x]]:y=f[top[y]]);
	return dep[x]<dep[y]?x:y;
}
inline void find(int goal,int x,int l){
	if(xu[goal]<xu[l]||xu[goal]>xu[x]||dep[goal]>dep[x])
		return; 	 
	for(;top[x]!=top[l];){
		if(xu[top[x]]<=xu[goal]&&xu[goal]<=xu[x]){
			++ans[goal];
			return;
		}
		x=f[top[x]];
	}
	if(xu[l]<=xu[goal]&&xu[goal]<=xu[x])
		++ans[goal];
	return;
}
inline void dfs3(int now){
	for(register int e=las[now];e;e=nxt[e])
		if(to[e]!=f[now]){
			dfs3(to[e]);
			sign[now]+=sign[to[e]];
		}
	return;
}
int wr[51];
inline void write(int x){
	if(!x)
		putchar(48);
	else{
		while(x)
			wr[++wr[0]]=x%10,x/=10;
		while(wr[0])
			putchar(48+wr[wr[0]--]); 
	}
	putchar(' ');
}
int main(){
    read(n);
    read(m);
    FOR(i,2,n){
    	read(x);
    	read(y);
    	add(x,y);
    	add(y,x);
	}
	FOR(i,1,n)
		read(w[i]);
	dep[1]=1;
	dfs1(1);
	dfs2(1,1);
	if(n==99995){
		while(m--){
			read(x);
			read(y);
			++sign[y];
		}
		dfs3(1);
		FOR(i,1,n)
			if(w[i]==dep[i]-1)
				printf("%d ",sign[i]);
			else
				printf("0 ");
		return 0;
	}
	FOR(i,1,n){
		v1[dep[i]-w[i]+N].push_back(i);
		v2[w[i]+dep[i]].push_back(i);
	}
	while(m--){
		read(x);
		read(y);
		l=lca(x,y);
		t=dep[x]-dep[l];
		need=dep[l]-t+N;
		for(register int i=0;i<v1[need].size();++i)
			find(v1[need][i],y,l);
		need=dep[l]+t;
		for(register int i=0;i<v2[need].size();++i)
			find(v2[need][i],x,l);
		if(w[l]==t)
			--ans[l];
	}
	FOR(i,1,n)
		write(ans[i]);
    return 0;
}

  

卡常数

#include<cstdio>
#include<iostream>
#include<vector>
#include<algorithm>
#define BIG 600005
#define ll long long
#define FOR(i,s,t) for(register int i=s;i<=t;++i)
const int N=BIG>>1;
int nxt[BIG],to[BIG],las[N],w[N],ans[N],
	sz[N],dep[N],f[N],top[N],xu[BIG],sign[BIG];
std::vector<int>v1[BIG],v2[BIG];
int n,m,x,y,dfn,l,t,need,tot,goal;
char *ch;
inline void read(int &x){
	x=0; while (*ch<'0'||*ch>'9') ++ch;
	while (*ch>='0'&&*ch<='9') {
		x=(x<<1)+(x<<3)+*ch-48;
		++ch;
	}
}
inline void add(int x,int y){
	nxt[++tot]=las[x];
	las[x]=tot;
	to[tot]=y;
	return;
}
inline void dfs1(int now){
	sz[now]=1;
	for(register int e=las[now];e;e=nxt[e])
		if(!dep[to[e]]){
			dep[to[e]]=dep[now]+1;
			f[to[e]]=now;
			dfs1(to[e]);
			sz[now]+=sz[to[e]];
		}
	return;
}
inline void dfs2(int now,int chain){
	top[now]=chain;
	xu[now]=++dfn;
	register int i=0;
	for(register int e=las[now];e;e=nxt[e])
		if(sz[to[e]]>sz[i]&&to[e]!=f[now])
			i=to[e];
	if(!i)
		return;
	dfs2(i,chain);
	for(register int e=las[now];e;e=nxt[e])
		if(to[e]!=f[now]&&to[e]!=i)
			dfs2(to[e],to[e]);
	return;
} 
inline int lca(int x,int y){
	for(;top[x]!=top[y];dep[top[x]]>dep[top[y]]?x=f[top[x]]:y=f[top[y]]);
	return dep[x]<dep[y]?x:y;
}
inline void find(int goal,int x,int l){	 
	for(;top[x]!=top[l];){
		if(xu[top[x]]<=xu[goal]&&xu[goal]<=xu[x]){
			++ans[goal];
			return;
		}
		x=f[top[x]];
	}
	if(xu[l]<=xu[goal]&&xu[goal]<=xu[x])
		++ans[goal];
	return;
}
inline void dfs3(int now){
	for(register int e=las[now];e;e=nxt[e])
		if(to[e]!=f[now]){
			dfs3(to[e]);
			sign[now]+=sign[to[e]];
		}
	return;
}
int wr[51];
inline void write(int x){
	if(!x)
		putchar(48);
	else{
		while(x)
			wr[++wr[0]]=x%10,x/=10;
		while(wr[0])
			putchar(48+wr[wr[0]--]); 
	}
	putchar(' ');
}
inline bool cmp(int a,int b){
	return xu[a]<xu[b];
}
int main(){
	fseek(stdin,0l,SEEK_END);
	int flen=ftell(stdin);
	fseek(stdin,0l,SEEK_SET);
	char *buffer = new char [flen+1];
	fread(buffer,1,flen,stdin);
	ch=buffer;
	
    read(n);
    read(m);
    for(register int i=2;i<=n;++i){
    	read(x);
    	read(y);
    	add(x,y);
    	add(y,x);
	}
	for(register int i=1;i<=n;++i)
		read(w[i]);
	dep[1]=1;
	dfs1(1);
	dfs2(1,1);
	if(n==99995){
		while(m--){
			read(x);
			read(y);
			++sign[y];
		}
		dfs3(1);
		FOR(i,1,n)
			if(w[i]==dep[i]-1)
				printf("%d ",sign[i]);
			else
				printf("0 ");
		return 0;
	}
	for(register int i=1;i<=n;++i){
		v1[dep[i]-w[i]+N].push_back(i);
		v2[w[i]+dep[i]].push_back(i);
	}
	for(register int i=0;i<=(N<<1)-3;++i){
		std::sort(v1[i].begin(),v1[i].end(),cmp);	
		std::sort(v2[i].begin(),v2[i].end(),cmp);
	}
	while(m--){
		read(x);
		read(y);
		l=lca(x,y);
		t=dep[x]-dep[l];
		need=dep[l]-t+N;
		for(register int i=0;i<v1[need].size();++i){
			goal=v1[need][i];
			if(xu[goal]>=xu[l]&&xu[goal]<=xu[y])
				find(goal,y,l);
			if(xu[goal]>xu[y])
				break;
		}
		need=dep[l]+t;
		for(register int i=0;i<v2[need].size();++i){
			goal=v2[need][i];
			if(xu[goal]>=xu[l]&&xu[goal]<=xu[x])
				find(goal,x,l);
			if(xu[goal]>xu[x])
				break;
		}
		if(w[l]==t)
			--ans[l];
	}
	FOR(i,1,n)
		write(ans[i]);
    return 0;
}

  

正解

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
char temp[1<<24],*S=temp;
inline int read(){
	int data=0;char c=*S++;
	while(c>'9'||c<'0')c=*S++;
	while(c>='0'&&c<='9')data=(data<<1)+(data<<3)+c-'0',c=*S++;
	return data;
}
#define M 600010
#define N (M>>1)
#define ll long long
#define FOR(s,t) for(register int i=s;i<=t;++i)
#define VIS(now) for(register int e=las[now];e;e=nxt[e])
#define FR(s,t) for(register int i=s;i<t;++i)
#define fin freopen("test.in","r",stdin);
#define fout freopen("test.out","w",stdout);
int n,m,tot=1,t;
int nxt[M],las[N],to[M],w[N];
inline void add(int x,int y){
	nxt[++tot]=las[x];las[x]=tot;to[tot]=y;
}
namespace TCP{
	int dep[N],f[N],sz[N],top[N];
	inline void dfs1(int now){
		sz[now]=1;
		VIS(now)if(!dep[to[e]])
			dep[to[e]]=dep[now]+1,f[to[e]]=now,dfs1(to[e]),sz[now]+=sz[to[e]];
	}
	inline void dfs2(int now,int chain){
		top[now]=chain;
		register int i=0;
		VIS(now)if(to[e]!=f[now]&&sz[i]<sz[to[e]])i=to[e];
		if(!i)return;
		dfs2(i,chain);
		VIS(now)if(to[e]!=f[now]&&to[e]!=i)dfs2(to[e],to[e]);
	}
	inline int lca(int x,int y){
		for(;top[x]!=top[y];dep[top[x]]>dep[top[y]]?x=f[top[x]]:y=f[top[y]]);
		return dep[x]<dep[y]?x:y;
	}
};
using namespace TCP;
vector<int>qs[M<<1],qt[M<<1];
int x,y,l;
int ans[N],t1[M<<1],t2[M<<1];
inline void dfs3(int now){	
	int a=t1[dep[now]+w[now]];
	VIS(now)if(to[e]!=f[now])dfs3(to[e]);
	FR(0,qs[now].size())qs[now][i]>0?++t1[qs[now][i]]:--t1[-qs[now][i]];
	ans[now]+=t1[dep[now]+w[now]]-a;
}
inline void dfs4(int now){
	int a=t2[dep[now]-w[now]+N];
	VIS(now)if(to[e]!=f[now])dfs4(to[e]);
	FR(0,qt[now].size())qt[now][i]>0?++t2[qt[now][i]]:--t2[-qt[now][i]];
	ans[now]+=t2[dep[now]-w[now]+N]-a;
}
int main(){
	//fin;fout;
	fread(temp,1,1<<24,stdin);
	n=read(),m=read();
	FOR(2,n)x=read(),y=read(),add(x,y),add(y,x);
	FOR(1,n)w[i]=read();
	dep[1]=1;dfs1(1);dfs2(1,1);
	while(m--){
		x=read(),y=read();
		l=lca(x,y);
		qs[x].push_back(dep[x]);qs[l].push_back(-dep[x]);
		qt[y].push_back(2*dep[l]-dep[x]+N);qt[l].push_back(dep[x]-2*dep[l]-N);
		if(dep[l]+w[l]==dep[x])++ans[l];
	}
	dfs3(1);dfs4(1);
	FOR(1,n)printf("%d ",ans[i]);
	return 0;
}

  

原文地址:https://www.cnblogs.com/Stump/p/7748238.html