Problem A 快递
根节点为$1$ , 含有$n$个节点的树,每一条边都有一段开放的时间$[s_i,e_i]$,和经过需要的时间。
有$q$组询问,每一次在时刻$t_i$出发从根节点出发走到第$u$个节点,沿着最短路走,询问是否可行。
注意到,当在边开放的时间走到这条边上均被认为合法,走出边的时间不会因此而限制。
对于$100\%$的数据,满足$1 \leq n,q \leq 5\times 10^5$
Solution :
考虑能否到达$u$的条件,就是能否在$u$上方的那条边$(fa,u)$的规定时间内到达该点的父亲$fa$。
我们注意到从根节点出发的时间为$time$,那么到达一个节点$u$的总时间就是这个点父亲前缀边的长度之和$pre$。
转化一下,能否到达这个点上方的那一条边的条件就是$time_u + pre \in [s_{Edge} , t_{Edge}]$
解出来就是$time_u \in [s_{Edge}-pre,t_{Edge}-pre]$
所以到达一个点既有当前点的限制,又有该点到根之间点的限制,所以我们只需要将这个点到根的所有点限制的区间交起来就可以了。
这样子,我们直接做一遍$dfs$即可,复杂度就是$O(n+q)$
# pragma GCC optimize(3) # include <bits/stdc++.h> # define inf (1e12) # define int long long # define Rint register int # define YES putchar('Y'),putchar('E'),putchar('S') # define NO putchar('N'),putchar('O') using namespace std; const int N = 5e5+10; struct A { int pre,to,w,s,t; }a[N<<1]; struct B { int l,r; }tim[N]; int tot,n,m; int head[N],d[N],f[N]; inline int read() { int X=0,w=0; char c=0; while(c<'0'||c>'9') {w|=c=='-';c=getchar();} while(c>='0'&&c<='9') X=(X<<3)+(X<<1)+(c^48),c=getchar(); return w?-X:X; } void adde(Rint u,Rint v,int w,int s,int t) { a[++tot].pre=head[u]; a[tot].to=v; a[tot].w=w; a[tot].s=s; a[tot].t=t; head[u]=tot; } void dfs(Rint u,Rint fa) { for (Rint i=head[u];i;i=a[i].pre) { int v=a[i].to; if (v==fa) continue; tim[v].l=max(tim[u].l,a[i].s-d[u]); tim[v].r=min(tim[u].r,a[i].t-d[u]); d[v]=d[u]+a[i].w; dfs(v,u); } } signed main() { n=read();m=read(); for (Rint i=2;i<=n;i++) { int u=read()+1,v=read()+1,w=read(),s=read(),t=read(); adde(u,v,w,s,t); adde(v,u,w,s,t); } tim[1].l=-inf; tim[1].r=inf; dfs(1,0); while (m--) { int u=read()+1,t=read(); (t>=tim[u].l && t<=tim[u].r)?(YES):(NO); putchar('\n'); } return 0; }