旅行(travel)

时间限制: 5 Sec 内存限制: 512 MB
题目描述
小R开车去C国旅行。C国所有n座城市构成一棵树,且树上的每条边的长度L_i满足1≤L_i≤2。小R打算白天开车,晚上到达一个城市后在该城市休息并为他的车加油。
有m个询问,每次询问小R开车从u到v,每天最多开p公里,至少需要多少天可以到达?注意,小R晚上必须到达某座城市,而不能将他的车停在某两座城市之间。
输入
第一行一个正整数n,表示点数。
接下来n-1行,每行三个正整数x,y,l,表示一条边的起点,终点和长度,保证1≤l≤2。
接下来一行一个正整数m,表示询问数。
接下来m行每行三个正整数u,v,p描述一个询问,分别表示旅行的起点,终点和每天能行驶的距离。保证p≥2。
输出
输出m行,第i表示第i个询问的答案。
样例输入
5
1 2 1
2 3 2
1 4 2
4 5 1
5
1 5 3
1 3 2
2 5 4
1 2 10
4 5 2
样例输出
1
2
1
1
1
提示

题解:
新奇的题目,理论上是以 n \sqrt n 为界,大于 n \sqrt n 的直接暴力,小于 n \sqrt n 的算出每个点往上走 p p 最远能到达哪个点,这里再倍增一下。
实际上以 n \sqrt n 为界有可能超时,我用 200 200 就没有超时。
o ( ( ) ) o o((⊙﹏⊙))o
C o d e Code:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
const int N=2e5+5;
int fa[N][20],tot,head[N],n,deep[N],dist[N],ans[N],pre[N][20];
inline int read()
{
	int x=0,f=1;
	char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while(s<='9'&&s>='0'){x=x*10+s-'0';s=getchar();}
	return x*f;
}
struct tree
{
	int x,y,z,id;
}a[N];
struct node
{
	int vet,next,len;
}edge[N];
void add(int u,int v,int w)
{
	edge[++tot].vet=v;
	edge[tot].next=head[u];
	head[u]=tot;
	edge[tot].len=w;
}
void dfs(int u,int father)
{
	for(int i=head[u];i;i=edge[i].next)
	{
		int v=edge[i].vet;
		if(v!=father)
		{
			fa[v][0]=u;
			deep[v]=deep[u]+1;
			dist[v]=dist[u]+edge[i].len;
			dfs(v,u);
		}
	}
}
int lca(int x,int y)
{
	if(deep[x]<deep[y])swap(x,y);
	int D=deep[x]-deep[y];
	for(int i=18;i>=0;i--)
		if(D&(1<<i))x=fa[x][i];
	for(int i=18;i>=0;i--)
		if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
	if(x==y)return x;
	return fa[x][0];
}
int cmp(tree x,tree y)
{
	return x.z<y.z;
}
int work(int u,int k)
{
	for(int i=18;i>=0;i--)
		if(fa[u][i]&&dist[u]-dist[fa[u][i]]<=k)
		{
			k-=dist[u]-dist[fa[u][i]];
			u=fa[u][i];
		}
	return u;
}
void print(int x)
{
	if(x<10)
	{
		putchar(x+'0');
		return;
	}
	print(x/10);
	putchar(x%10+'0');
}
int main()
{
	deep[0]=-1;
	n=read();
	int K=200;
	for(int i=1;i<n;i++)
	{
		int u=read(),v=read(),w=read();
		add(u,v,w);add(v,u,w);
	}
	dfs(1,-1);
	for(int j=1;j<=18;j++)
		for(int i=1;i<=n;i++)
			fa[i][j]=fa[fa[i][j-1]][j-1];
	int m=read();
	for(int i=1;i<=m;i++)
	{
		a[i].x=read();a[i].y=read();
		a[i].z=read();a[i].id=i;
	}
	sort(a+1,a+m+1,cmp);
	int last=1;
	for(int i=1;i<=m;i=last)
	{
		while(last<=m&&a[i].z==a[last].z)last++;
		if(a[i].z<=K)
		{
			for(int j=1;j<=n;j++)pre[j][0]=work(j,a[i].z);
			for(int k=1;k<=18;k++)
				for(int j=1;j<=n;j++)
					pre[j][k]=pre[pre[j][k-1]][k-1];
			for(int j=i;j<last;j++)
			{
				int u=a[j].x,v=a[j].y;
				int w=lca(u,v);
				for(int k=18;k>=0;k--)
					if(deep[pre[u][k]]>deep[w])
					{
						ans[a[j].id]+=1<<k;
						u=pre[u][k];
					}
				for(int k=18;k>=0;k--)
					if(deep[pre[v][k]]>deep[w])
					{
						ans[a[j].id]+=1<<k;
						v=pre[v][k];
					}
				if(dist[u]+dist[v]-dist[w]*2<=a[j].z)
					ans[a[j].id]++;else ans[a[j].id]+=2;
			}
		}else
		{
			for(int j=i;j<last;j++)
			{
				int u=a[j].x,v=a[j].y;
				int w=lca(u,v),t;
				t=work(u,a[j].z);
				while(deep[t]>deep[w])
				{
					ans[a[j].id]++;
					u=t;
					t=work(u,a[j].z);
				}
				t=work(v,a[j].z);
				while(deep[t]>deep[w])
				{
					ans[a[j].id]++;
					v=t;
					t=work(v,a[j].z);
				}
				if(dist[u]+dist[v]-dist[w]*2<=a[j].z)
					ans[a[j].id]++;else ans[a[j].id]+=2;
			}
		}
	}
	for(int i=1;i<=m;i++)
	{
		print(ans[i]);
		puts("");
	}
	return 0;
}
发布了232 篇原创文章 · 获赞 463 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/qq_34531807/article/details/82928023