题意:给出一个$N$个点、$M$条边的图,每条边有长度和海拔,$Q$组询问,每一次询问从$v$开始,经过海拔超过$p$的边所能到达的所有点中到点$1$的最短路的最小值,强制在线。$N \leq 2 \times 10^5 , M , Q \leq 4 \times 10^5$
关于$SPFA...$
与边的权值有关的连通块问题,经常可以考虑到$Kruskal$重构树。我们以海拔从大到小构建$Kruskal$重构树,那么对于每一次询问,可以到达的点就对应$Kruskal$重构树上的一棵子树。我们对于每一个点记录它的子树的叶子节点的最短路的最小值,每一次倍增找到询问对应的那一棵子树就能得到答案了。
#include<bits/stdc++.h> //This code is written by Itst using namespace std; inline int read(){ int a = 0; bool f = 0; char c = getchar(); while(c != EOF && !isdigit(c)){ if(c == '-') f = 1; c = getchar(); } while(c != EOF && isdigit(c)){ a = (a << 3) + (a << 1) + (c ^ '0'); c = getchar(); } return f ? -a : a; } const int MAXN = 400010; struct edge{ int start , end , hei; }now[MAXN]; struct Edge{ int end , upEd , w; }Ed[MAXN << 1]; int head[MAXN] , minDis[MAXN] , fa[MAXN << 1] , jump[MAXN << 1][20] , val[MAXN << 1] , ans[MAXN << 1] , ch[MAXN << 1][2] , cntNode , cntEd , N , M , Q; priority_queue < pair < int , int > > q; bool operator <(edge a , edge b){ return a.hei > b.hei; } int find(int a){ return fa[a] == a ? a : (fa[a] = find(fa[a])); } inline void addEd(int a , int b , int c){ Ed[++cntEd].end = b; Ed[cntEd].upEd = head[a]; Ed[cntEd].w = c; head[a] = cntEd; } void Dijk(){ memset(minDis , 0x7f , sizeof(minDis)); minDis[1] = 0; q.push(make_pair(0 , 1)); while(!q.empty()){ pair < int , int > t = q.top(); q.pop(); if(-t.first > minDis[t.second]) continue; for(int i = head[t.second] ; i ; i = Ed[i].upEd) if(minDis[Ed[i].end] > minDis[t.second] + Ed[i].w){ minDis[Ed[i].end] = minDis[t.second] + Ed[i].w; q.push(make_pair(-minDis[Ed[i].end] , Ed[i].end)); } } } void dfs(int node){ if(!node) return; for(int i = 1 ; i <= 19 && jump[node][i - 1] ; ++i) jump[node][i] = jump[jump[node][i - 1]][i - 1]; dfs(ch[node][0]); dfs(ch[node][1]); } inline int jumpToAll(int x , int h){ for(int i = 19 ; i >= 0 ; --i) if(val[jump[x][i]] > h) x = jump[x][i]; return x; } int main(){ #ifndef ONLINE_JUDGE freopen("4768.in" , "r" , stdin); //freopen("4768.out" , "w" , stdout); #endif for(int T = read() ; T ; --T){ memset(jump , 0 , sizeof(jump)); memset(ch , 0 , sizeof(ch)); memset(head , 0 , sizeof(head)); cntEd = 0; N = read(); M = read(); for(int i = 1 ; i <= M ; i++){ int a = read() , b = read() , c = read() , d = read(); now[i].start = a; now[i].end = b; now[i].hei = d; addEd(a , b , c); addEd(b , a , c); } Dijk(); for(int i = 1 ; i <= N ; i++){ fa[i] = i; ans[i] = minDis[i]; } sort(now + 1 , now + M + 1); cntNode = N; for(int i = 1 ; i <= M ; ++i) if(find(now[i].start) != find(now[i].end)){ int a = find(now[i].start) , b = find(now[i].end); fa[a] = fa[b] = jump[a][0] = jump[b][0] = ++cntNode; ch[cntNode][0] = a; ch[cntNode][1] = b; val[cntNode] = now[i].hei; ans[cntNode] = min(ans[a] , ans[b]); fa[cntNode] = cntNode; } dfs(cntNode); int lastans = 0 , Q = read() , K = read() , S = read(); while(Q--){ int a = read() , b = read(); a = (0ll + a + K * lastans - 1) % N + 1; b = (0ll + b + K * lastans) % (S + 1); int t = jumpToAll(a , b); printf("%d\n" , lastans = ans[t]); } } return 0; }