归程
Luogu
LOJ
UOJ
BZOJ
不难发现一定是先开车走一段路直到下条边海拔不超过水位,然后下车沿最短路走到(1)号点。
按海拔降序建出Kruskal重构树,对于一次询问,找到(v)的祖先中深度最低的海拔高于水位低的点(u),那么(u)的子树中的叶子节点就是(v)可以开车到的点。
预处理每个点到(1)号点的最短路(dis),然后维护每个节点子树中的叶子节点最小(dis)即可。
#include<bits/stdc++.h>
#define M 400007
#define N 200007
using namespace std;
namespace IO
{
char ibuf[(1<<21)+1],obuf[(1<<21)+1],st[15],*iS,*iT,*oS=obuf,*oT=obuf+(1<<21);
char Get() { return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++); }
void Flush() { fwrite(obuf,1,oS-obuf,stdout),oS=obuf; }
void Put(char x) { *oS++=x; if(oS==oT) Flush(); }
int read(){int x=0;char ch=Get();while(ch>57||ch<48)ch=Get();while(ch>=48&&ch<=57)x=x*10+(ch^48),ch=Get();return x;}
void write(int x) {int top=0; if(!x) Put('0'); while(x) st[++top]=(x%10)+48,x/=10; while(top) Put(st[top--]); Put('
'); }
}
using namespace IO;
struct EDGE{int u,v,w;}Edge[M];
int operator<(EDGE a,EDGE b){return a.w>b.w;}
struct dot{int u,d;};
int operator<(dot a,dot b){return a.d>b.d;}
priority_queue<dot>q;
int tot,head[N<<1],ver[M<<1],Next[M<<1],edge[M<<1],dis[N<<1],vis[N],dep[N<<1],val[N<<1],fa[N<<1],f[N<<1][20];
void add(int u,int v,int w=0){ver[++tot]=v,Next[tot]=head[u],edge[tot]=w,head[u]=tot;}
int Find(int x){return x==fa[x]? x:fa[x]=Find(fa[x]);}
void dfs(int u,int Fa)
{
dep[u]=dep[Fa]+1,f[u][0]=Fa;
for(int i=1;i<=19;++i) f[u][i]=f[f[u][i-1]][i-1];
for(int i=head[u],v;i;i=Next[i]) dfs(v=ver[i],u),dis[u]=min(dis[u],dis[v]);
}
int query(int u,int p)
{
for(int i=19;~i;--i) if((dep[u]>1<<i)&&val[f[u][i]]>p) u=f[u][i];
return dis[u];
}
int main()
{
int T,i,n,m,u,v,w,l,lastans,cnt,Q,K,S,num;
for(T=read();T;--T)
{
num=lastans=tot=0,n=read(),m=read(),memset(head,0,sizeof head),memset(f,0,sizeof f);
for(i=1;i<=m;++i) u=read(),v=read(),l=read(),w=read(),add(u,v,l),add(v,u,l),Edge[i]=EDGE{u,v,w};
memset(vis,0,sizeof vis),memset(dis,0x3f,sizeof dis),dis[1]=0,q.push(dot{1,0});
while(!q.empty())
{
u=q.top().u,q.pop();
if(vis[u]) continue;
for(vis[u]=1,i=head[u];i;i=Next[i]) if(!vis[v=ver[i]]&&dis[v]>dis[u]+edge[i]) dis[v]=dis[u]+edge[i],q.push(dot{v,dis[v]});
}
memset(head,0,sizeof head),tot=0,cnt=n,sort(Edge+1,Edge+m+1);
for(i=1;i<=n<<1;++i) fa[i]=i;
for(i=1;i<=m;++i) if((u=Find(Edge[i].u))^(v=Find(Edge[i].v))){val[++cnt]=Edge[i].w,fa[u]=fa[v]=cnt,add(cnt,u),add(cnt,v),++num;if(num==n-1)break;};
dfs(cnt,0);
Q=read(),K=read(),S=read();
while(Q--) u=(K*lastans+read()-1)%n+1,v=(K*lastans+read())%(S+1),write(lastans=query(u,v));
}
return Flush(),0;
}
屠龙勇士
#include<set>
#include<cctype>
#include<cstdio>
#include<algorithm>
using i64=long long;
const int N=100007;
i64 a[N],b[N],p[N];
i64 read(){i64 x=0;char c=getchar();while(isspace(c))c=getchar();while(isdigit(c))(x*=10)+=c&15,c=getchar();return x;}
i64 gcd(i64 n,i64 m){return !m? n:gcd(m,n%m);}
void exgcd(i64 a,i64 b,i64&x,i64&y){!b? (x=1,y=0):(exgcd(b,a%b,y,x),y-=a/b*x);}
i64 mul(i64 a,i64 b,i64 p){return (__int128)a*b%p;}
void solve()
{
int n=read(),m=read(),flg=!n||!!m;std::multiset<i64>s;
for(int i=1;i<=n;++i) a[i]=read();
for(int i=1;i<=n;++i) p[i]=read();
for(int i=1;i<=n;++i) b[i]=read();
for(int i=1;i<=m;++i) s.insert(read());
i64 lim=0,A=0,B=1;
for(int i=1;i<=n&&flg;++i)
{
auto it=s.upper_bound(a[i]);
if(it!=s.begin()) --it;
i64 q=*it;
s.erase(it),s.insert(b[i]),lim=std::max(lim,(a[i]+q-1)/q),a[i]%=p[i],q%=p[i];
i64 g=gcd(B*q,p[i]),x,y;
if((a[i]-q*A)%g) {flg=0;break;}
exgcd(B*q,p[i],x,y),x=mul(x,(a[i]-q*A)/g,p[i]),y=p[i]/g*B,A=(A+mul(B,x,y))%y,B=y;
}
printf("%lld
",flg? (lim-A+B-1)/B*B+A:-1);
}
int main()
{
for(int t=read();t;--t) solve();
}