题目:luogu4768.
题目大意:给定一张
n
n
n个点
m
m
m条边的无向图.现在给定
q
q
q组询问,每次询问
v
,
p
v,p
v,p表示从点
v
v
v出发,可以通过所有边权大于
p
p
p的边走到任意一个点,从这个点到
1
1
1的最短路长度最小,求最短路.
数据组数
≤
3
\leq 3
≤3,
1
≤
n
≤
2
∗
1
0
5
,
1
≤
m
,
q
≤
4
∗
1
0
5
1\leq n\leq 2*10^5,1\leq m,q\leq 4*10^5
1≤n≤2∗105,1≤m,q≤4∗105,强制在线.
首先肯定得求出点 1 1 1到每个点的最短路,那就先跑个堆优化dijkstra好了.
然后可以先考虑离线算法,很容易想到用把所有询问按照 p p p从大到小排序,每次都把大于 p p p的边加入,用并查集维护一下所有点之间的连通性,找到与 v v v连通的点里面到 1 1 1最短路最小的值即可.时间复杂度 O ( n log n ) O(n\log n) O(nlogn).
考虑如何在线,好像维护个可持久化并查集就好了,但是这样子貌似代码量有点大,而且速度有点慢…
于是我们自然而然想到了Kruskal重构树.这玩意大概就是说,我们将边按照边权从大到小排序,按照这个顺序进行合并.每当两个并查集合并的时候,我们建立一个新点作为它们的根,根的点权为这条边的边权.那么当两个点连通必然满足它们的LCA的点权大于 p p p.
那么现在我们要查询一个点所在连通块到 1 1 1的最短路的最小值就只需要跑到一个最上方的祖先满足点权大于 p p p,然后这个祖先的子树最小值即为答案,跳祖先通过树上倍增实现,子树最小值直接预处理即可.
时间复杂度仍然是 O ( n log n ) O(n\log n) O(nlogn)的.
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=200000,M=400000,INF=(1<<30)-1,C=20;
int n,m;
struct side{
int y,next,v;
}e[M*2+9];
int lin[N+9],top;
void ins(int x,int y,int v){
e[++top].y=y;e[top].v=v;
e[top].next=lin[x];
lin[x]=top;
}
struct state{
int x,v;
state(int X=0,int V=0){x=X;v=V;}
bool operator > (const state &p)const{return v>p.v;}
};
priority_queue<state,vector<state>,greater<state> >q;
int dis[N+9],use[N+9];
void dijkstra(int st){
for (int i=1;i<=n;++i) dis[i]=INF,use[i]=0;
q.push(state(st,0));dis[st]=0;
while (!q.empty()){
int t=q.top().x;q.pop();
if (use[t]) continue;
use[t]=1;
for (int i=lin[t];i;i=e[i].next)
if (dis[t]+e[i].v<dis[e[i].y]){
dis[e[i].y]=dis[t]+e[i].v;
q.push(state(e[i].y,dis[e[i].y]));
}
}
}
struct tree{
int fa,s[2],v;
}tr[N*2+9];
int fa[N*2+9],cn;
int get(int u){return u^fa[u]?fa[u]=get(fa[u]):u;}
struct side2{
int x,y,v;
bool operator < (const side2 &p)const{return v<p.v;}
}e2[N*2+9];
void Build_kruskal(){
sort(e2+1,e2+1+m);
int u,v;
for (int i=1;i<=n<<1;++i) fa[i]=i;
for (int i=1;i<=n;++i) tr[i]=tree(),tr[i].v=INF;
cn=n;
for (int i=m;i>=1;--i){
u=get(e2[i].x);v=get(e2[i].y);
if (u==v) continue;
fa[u]=fa[v]=++cn;
tr[cn]=tree();
tr[cn].s[0]=u;tr[cn].s[1]=v;
tr[u].fa=tr[v].fa=cn;
tr[cn].v=e2[i].v;
}
}
int mn[N*2+9],gr[N*2+9][C+1];
void dfs(int k){
gr[k][0]=tr[k].fa;
for (int i=1;i<=C;++i)
gr[k][i]=gr[gr[k][i-1]][i-1];
if (k<=n){mn[k]=dis[k];return;}
else mn[k]=INF;
for (int i=0;i<2;++i){
dfs(tr[k].s[i]);
mn[k]=min(mn[k],mn[tr[k].s[i]]);
}
}
int solve(int st,int p){
int x=st;
for (int i=C;i>=0;--i)
if (tr[gr[x][i]].v>p) x=gr[x][i];
return mn[x];
}
Abigail start(){
for (int i=1;i<=top;++i) e[i]=side();
for (int i=1;i<=n;++i) lin[i]=0;
top=0;
}
Abigail into(){
scanf("%d%d",&n,&m);
int v;
for (int i=1;i<=m;++i){
scanf("%d%d%d%d",&e2[i].x,&e2[i].y,&v,&e2[i].v);
ins(e2[i].x,e2[i].y,v);ins(e2[i].y,e2[i].x,v);
}
}
Abigail work(){
dijkstra(1);
Build_kruskal();
dfs(cn);
}
Abigail getans(){
int q,k,last=0,v,p,s;
scanf("%d%d%d",&q,&k,&s);
while (q--){
scanf("%d%d",&v,&p);
v=(v+k*last-1)%n+1;
p=(p+k*last)%(s+1);
printf("%d\n",last=solve(v,p));
}
}
int main(){
int T;
scanf("%d",&T);
while (T--){
start();
into();
work();
getans();
}
return 0;
}