传送门
首先考虑暴力做法:我们可以在任意一个海拔高于水位线的点下车,从这些点出发,到
1
1
1号点会有一个最短距离。我们只要找出这些距离中的最短距离即可。这个东西可以先用
d
i
j
k
s
t
r
a
dijkstra
dijkstra处理一下。
而对于这种要求出一个点在边有限制下的可达点的问题(边权大等于某个数或小等于某个数),往往可以联想到 k r u s k a l kruskal kruskal重构树。它有几个性质(以下摘自这里):
①是一个二叉树
②如果是按最小生成树建立的话是一个大根堆
③任意两个点路径上边权的最大值(按照最小生成树建)为它们的LCA的点权
④最小生成树上的点都是叶子节点。
那么我们可以根据海拔建立出一个最大生成树。对于某一个点
u
u
u的可达点,我们可以先在重构树上倍增往上跳,跳到海拔高于水位线的海拔最小的点。那么它在重构树的子树中的点(叶子结点)都是
u
u
u的可达点。我们只需知道子树中最小值。
于是在建好重构树后,
d
f
s
dfs
dfs一下处理每个点子树的最小值就好了。。
要多加注意一下预处理和清空数组。。忘记预处理倍增数组居然可以过样例-_-
#include<bits/stdc++.h>
#define pii pair<int,int>
#define mp make_pair
using namespace std;
const int maxn=2e5+10,maxm=4e5+10,Log=18,oo=2e9+10;
int T,n,m,Q,K,S,v,p,num,dis[maxn],lastans=0;
int fa[maxm],f[maxm][Log],val[maxm],lc[maxm],rc[maxm],mn[maxm];
int Head[maxn],V[maxm<<1],W[maxm<<1],Next[maxm<<1],cnt=0;
struct edge{int u,v,l,a;}e[maxm];
inline bool operator<(const edge &a,const edge &b){return a.a>b.a;}
inline int read(){
int x=0;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
return x;
}
inline void add(int u,int v,int w){Next[++cnt]=Head[u],V[cnt]=v,W[cnt]=w,Head[u]=cnt;}
inline void dijkstra(int s=1){
priority_queue<pii> Q;
for(int i=1;i<=n;++i) dis[i]=oo;
dis[s]=0;Q.push(mp(0,s));
while(!Q.empty()){
int u=Q.top().second;Q.pop();
for(int i=Head[u];i;i=Next[i]){
if(dis[V[i]]>dis[u]+W[i]){
dis[V[i]]=dis[u]+W[i];
Q.push(mp(-dis[V[i]],V[i]));
}
}
}
}
inline int getfa(int x){return x==fa[x]?x:fa[x]=getfa(fa[fa[x]]);}
inline void kruskal(int numedge=0){
num=n,sort(e+1,e+m+1);
for(int i=1;i<=n;++i) fa[i]=i,mn[i]=oo;
for(int i=1;i<=m;++i){
int fx=getfa(e[i].u),fy=getfa(e[i].v);
if(fx!=fy){
fa[fx]=fa[fy]=fa[++num]=num,mn[num]=oo,val[num]=e[i].a;
f[fx][0]=f[fy][0]=num,lc[num]=fx,rc[num]=fy,++numedge;
}if(numedge==n-1) break;
}
}
inline int getpos(int u,int h){
for(int i=Log-1;i>=0;--i)
if(f[u][i]&&val[f[u][i]]>h) u=f[u][i];
return u;
}
inline void dfs(int u){
for(int i=1;i<Log;++i) f[u][i]=f[f[u][i-1]][i-1];
if(!lc[u]&&!rc[u]){mn[u]=dis[u];return;}
if(lc[u]) dfs(lc[u]),mn[u]=min(mn[u],mn[lc[u]]);
if(rc[u]) dfs(rc[u]),mn[u]=min(mn[u],mn[rc[u]]);
}
inline void init(){
cnt=0,memset(Head,0,sizeof(Head));
lastans=0,memset(f,0,sizeof(f)),memset(fa,0,sizeof(fa));
memset(lc,0,sizeof lc),memset(rc,0,sizeof rc);
}
int main(){
freopen("return.in","r",stdin);
freopen("return.out","w",stdout);
T=read();
while(T--){
n=read(),m=read(),init();
for(int i=1;i<=m;++i){
e[i].u=read(),e[i].v=read(),e[i].l=read(),e[i].a=read();
add(e[i].u,e[i].v,e[i].l),add(e[i].v,e[i].u,e[i].l);
}dijkstra(),kruskal(),dfs(num),Q=read(),K=read(),S=read();
while(Q--){
v=(read()+K*lastans-1)%n+1,p=(read()+K*lastans)%(S+1);
v=getpos(v,p),printf("%d\n",lastans=mn[v]);
}
}
}