旅行(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
提示
题解:
新奇的题目,理论上是以为界,大于的直接暴力,小于的算出每个点往上走最远能到达哪个点,这里再倍增一下。
实际上以为界有可能超时,我用就没有超时。
#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;
}