【题解】洛谷P1600 天天爱跑步(60分暴力)

NOIP2016最难的一道题目,正解不会系列。。

然而那年每道题都有比较详细的分段范围,所以我们可以尝试拿到部分分。这里提供部分分为60分的做法。

Sample 1 2

只有当某个点时刻为0时才有可能观察到选手 因此我们先将初始状态每个点的选手数目统计下来 然后对每个点的时间遍历 如果时间为0输出该点选手数目 否则输出0

Sample 3 4

由于时间为0, 所以我们将初始状态每个点的选手数目统计下来后直接输出即可。

Sample 5

其实想到这个做法后可以用这个做法解决Sample 1 2 3 4。由于数据范围在1000以内,所以我们对于每个询问都从初始点爆搜,如果深度步数相同就给当前节点+1,注意终点特判。

Sample 6 7 8

数据范围变大了,但我们仍然有比较好的解决方法。由于是一条链,所以我们只需要把询问的起点和终点连边即可。然后我们对于每个点设x,y代表其往前或往后走t[i]所到达的结点。当符合范围内时,如果连边后该节点所到达的结点超过了询问的终止节点,那么肯定在t[i]的时间内能正好到达那个点,给那个点的答案+1即可。

Sample 9 10 11 12

由于都是从起点出发,我们可以记录下每个节点的深度,并开一个size数组记录每个点的子树内所包含的目标终点的个数。首先终点所在的点的size要初始化为1,然后对于时间等于深度的结点我们记录下其size值,dfs内size[x]+=size[y]

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
using namespace std;
const int maxn=300010;
const int maxm=300010;
int n,m;
int head[maxn],nnext[maxm*2],to[maxm*2],t[maxn];
bool b[maxn];
int size[maxn];
int ob[maxn];
int tot;
int depth[maxn],fa[maxn];
struct player
{
	int s;
	int t;
}a[maxm];
void add(int x,int y)
{
	tot++;
	nnext[tot]=head[x];
	head[x]=tot;
	to[tot]=y;
}
void dfs(int x)
{
	for(int i=head[x];i;i=nnext[i])
	{
		int y=to[i];
		if(y==fa[x]) continue;
		fa[y]=x;
		depth[y]=depth[x]+1;
		dfs(y);
	}
}
void ddfs(int x,int step)
{
	for(int i=head[x];i;i=nnext[i])
	{
		int y=to[i];
		if(y==fa[x]) continue;
		ddfs(y,step+1);
		size[x]+=size[y];
	}
	if(t[x]==step)
	{
		ob[x]=size[x];
	}
} 
bool dfs1(int x,int fa,int y,int step)
{
	if(x==y)
	{
		if(t[y]==step) ob[y]++;
		return true;
	}
	for(int i=head[x];i;i=nnext[i])
	{
		int go=to[i];
		if(go==fa) continue;
		if(dfs1(go,x,y,step+1)==true)
		{
			if(t[x]==step) ob[x]++;
			return true;
		}
	}
	return false;
}
int main()
{
//	freopen("running.in","r",stdin);
//	freopen("running.out","w",stdout);
	scanf("%d%d",&n,&m);
	//sample 6 7 8
	if(n==99994)
	{
		for(int i=1;i<=n-1;i++)
		{
			int x,y;
			scanf("%d%d",&x,&y);
		}
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&t[i]);
		}
		for(int i=1;i<=m;i++)
		{
			int s,t;
			scanf("%d%d",&s,&t);
			add(s,t);
		}
		for(int i=1;i<=n;i++)
		{
			int x=i-t[i];
			int y=i+t[i];
			if(x>=1)
			{
				for(int j=head[x];j;j=nnext[j])
				{
					if(to[j]>=i) ob[i]++;
				}
			}
			if(y<=n)
			{
				for(int j=head[y];j;j=nnext[j])
				{
					if(to[j]<=i) ob[i]++;
				}
			}
		}
		for(int i=1;i<=n;i++)
		{
			printf("%d ",ob[i]);
		}
		return 0;
	}
	//sample 5
	if(n==993)
	{
		for(int i=1;i<=n-1;i++)
		{
			int x,y;
			scanf("%d %d",&x,&y);
			add(x,y);
			add(y,x);
		}
		for(int i=1;i<=n;i++) 
		{
			scanf("%d",&t[i]);
		}
		for(int i=1;i<=m;i++)
		{
			int s,t;
			scanf("%d %d",&s,&t);
			dfs1(s,0,t,0);
		}
		for(int i=1;i<=n;i++)
		{
			printf("%d ",ob[i]);
		}
		return 0;
	}
	for(int i=1;i<=n-1;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&t[i]);
	}
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&a[i].s,&a[i].t);
	}
	
	// sample 3 and 4 
	bool flag;
	for(int i=1;i<=n;i++)
	{
		if(t[i]!=0) flag=true;
	}
	if(flag==false)
	{
		for(int i=1;i<=m;i++)
		{
			ob[a[i].s]++;
		}
		for(int i=1;i<=n;i++)
		{
			cout<<ob[i]<<' ';
		}
		return 0;
	}
	//sample 1 and 2
	bool flag1;
	for(int i=1;i<=m;i++)
	{
		if(a[i].s!=a[i].t) flag1=true;
	}
	if(flag1==false)
	{
		for(int i=1;i<=m;i++)
		{
			ob[a[i].s]++;
		}
		for(int i=1;i<=n;i++)
		{
			if(t[i]!=0) cout<<"0"<<' ';
			else cout<<ob[i]<<' ';
		}
		return 0;
	}
	// sample 9 10 11 12
	bool flag2;
	for(int i=1;i<=m;i++)
	{
		if(a[i].s!=1) flag2=true;
	}
	if(flag2==false)
	{
		depth[1]=0;
		dfs(1);
		for(int i=1;i<=m;i++)
		{
			size[a[i].t]++;
		}
		
		ddfs(1,0);
		for(int i=1;i<=n;i++)
		{
			printf("%d ",ob[i]);
		}
		
		return 0;
	}
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Rem_Inory/article/details/81779288