# 解法

$O\left(N\mathrm{lg}N（Dijsktra）+\left(M\mathrm{lg}M+M\mathrm{lg}N\right)（最大生成树）+N\mathrm{lg}N（排序）+Q\mathrm{lg}N（询问）\right)\phantom{\rule{0ex}{0ex}}=O\left(M\mathrm{lg}M+\left(N+M+Q\right)\mathrm{lg}N\right)$$O(N \lg N（Dijsktra）+(M\lg M+M\lg N)（最大生成树）+N \lg N（排序）+Q \lg N （询问）) \\=O(M\lg M+(N+M+Q)\lg N)$

# 代码

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 200000
#define MAXM 400000
int n,m;
struct edge
{
int u,v,l,a;
} ed[MAXM+1];
bool cmped(const edge &x,const edge &y)
{
return x.a>y.a;
}
struct EDGE
{
int to,l,a;
EDGE *las;
} e[MAXM*2];
int ne;
EDGE *last[MAXN+1];
void link(int u,int v,int l,int a)
{
e[ne].to=v,e[ne].l=l,e[ne].a=a;
e[ne].las=last[u];
last[u]=e+ne;
++ne;
}
long long dis[MAXN+1];
void Shortest_Path();
int Q,K,S;
struct Change_List
{
int x,a;
long long ans;
} cl[MAXN*2+1];
int ncl;
bool cmpcl(const Change_List &u,const Change_List &v)
{
return u.x<v.x || u.x==v.x && (u.a>v.a || u.a==v.a && u.ans>v.ans);
}
int ac[MAXN+1];
struct Union_Find_Set
{
int fa;
int a;
long long ans;
int dep;
} ufs[MAXN+1];
int getfa(int x)
{
while (ufs[x].fa!=x)
x=ufs[x].fa;
return x;
}
int main()
{
//  freopen("return.in","r",stdin);
//  freopen("return.out","w",stdout);
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
int T;
scanf("%d",&T);
while (T--)
{
scanf("%d%d",&n,&m);
memset(last,0,sizeof last);
ne=0;
for (int i=1;i<=m;++i)
{
int u,v,l,a;
scanf("%d%d%d%d",&u,&v,&l,&a);
ed[i].u=u,ed[i].v=v,ed[i].l=l,ed[i].a=a;
}
scanf("%d%d%d",&Q,&K,&S);
Shortest_Path();
sort(ed+1,ed+m+1,cmped);
for (int i=1;i<=n;++i)
{
ufs[i].fa=i;
ufs[i].a=S+1;
ufs[i].ans=dis[i];
ufs[i].dep=1;
}
ncl=0;
for (int i=1;i<=n;++i)
{
++ncl;
cl[ncl].x=i;
cl[ncl].ans=dis[i];
cl[ncl].a=S+1;
}
for (int i=1;i<=m;++i)
{
int x=getfa(ed[i].u),y=getfa(ed[i].v);
if (x!=y)
{
//x->y
if (ufs[x].dep>ufs[y].dep)
swap(x,y);
ufs[x].fa=y;
ufs[x].a=ed[i].a;
ufs[y].dep=max(ufs[y].dep,ufs[x].dep+1);
if (ufs[x].ans<ufs[y].ans)
{
ufs[y].ans=ufs[x].ans;
++ncl;
cl[ncl].x=y;
cl[ncl].ans=ufs[x].ans;
cl[ncl].a=ed[i].a;
}
}
}
sort(cl+1,cl+ncl+1,cmpcl);
for (int i=1,j=0;i<=ncl;++i)
if (cl[i-1].x!=cl[i].x)
ac[j++]=i-1;
ac[n]=ncl;
long long lastans=0;
while (Q--)
{
int v,p;
scanf("%d%d",&v,&p);
v=(v+K*lastans-1)%n+1;
p=(p+K*lastans)%(S+1);
while (v!=ufs[v].fa && p<ufs[v].a)
v=ufs[v].fa;
int l=ac[v-1]+1,r=ac[v],res=-1;
while (l<=r)
{
int mid=l+r>>1;
if (p<cl[mid].a)
l=(res=mid)+1;
else
r=mid-1;
}
lastans=cl[res].ans;
printf("%lld\n",lastans);
}
}
return 0;
}
bool cmph(int son,int fa)
{
return dis[son]>dis[fa];
}
int h[MAXN],nh;
bool bz[MAXN+1];
void Shortest_Path()
{
memset(dis+1,127,sizeof(long long)*n);
memset(bz+1,0,sizeof(bool)*n);
dis[1]=0;
nh=1;
h[0]=1;
bz[1]=1;
while (nh)
{
int top=h[0];
pop_heap(h,h+nh--,cmph);
for (EDGE *ei=last[top];ei;ei=ei->las)
if (dis[top]+ei->l<dis[ei->to])
{
dis[ei->to]=dis[top]+ei->l;
if (!bz[ei->to])
{
bz[ei->to]=1;
h[nh++]=ei->to;
push_heap(h,h+nh,cmph);
}
}
bz[top]=0;
}
}

# Others

1、 我比赛时没切题，是因为数组开小了……
2、 其实这个程序还有改进的地方，比如，在这题中，一些边的海拔是相同的，但我在最大生成树是会记录多条修改信息，其实可以并在一起。改起来也简单，但我懒得改了。