最小生成树
最小生成树为边权和最小的生成树
kruskal
贪心地,每次都加边权最小的边,如果这条边的两个端点已联通就不加
将两集合并入一个集合,查询两点是否在同一集合,用并查集维护
证明不会
重构树
当加入一条边时,建一个虚点当作这两点的父亲的父亲,点权为这条边的边权
重构树有重要性质:虚点点权从叶子到根非降或非升
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#define sf scanf
#define pf printf
#define mp make_pair
#define fo(i,x,y) for(register int i = x;i<=y;++i)
#define go(i,x,y) for(register int i = x;i>=y;--i)
using namespace std;
const int maxn = 200005;
const int maxm = 400005;
const int inf = 2147483647;
const int mod = 1000000007;
int T,n,m;
struct node1{
int v,l,a;
};
vector<node1> e1[maxn];
void add1(int u,int v,int l,int a){
e1[u].push_back(node1{v,l,a});
}
int dis[maxn];
bool vis[maxn];
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q;
struct node2{
int u,v,l,a;
}e2[maxm];
bool cmp(node2 x,node2 y){
return x.a > y.a;
}
int fa[maxn+maxn];
int getf(int x){
return fa[x]<0?x:(fa[x]=getf(fa[x]));
}
int cnt_point;
vector<int> e3[maxn+maxn];
void add3(int u,int v){
e3[u].push_back(v);
}
int stp[maxn+maxn][20],minv[maxn+maxn],dep[maxn+maxn],mind[maxn+maxn];
void clear_data(){
memset(vis,0,sizeof vis);
memset(dis,0x3f,sizeof(dis));
dis[1] = 0;
while(q.size()) q.pop();
fo(i,1,400000) fa[i] = -1;
fo(i,1,400000)
while(e3[i].size())
e3[i].pop_back();
fo(i,1,200000)
while(e1[i].size())
e1[i].pop_back();
}
void read(){
cin>>n>>m;
fo(i,1,m){
int u,v,l,a;
cin>>u>>v>>l>>a;
e2[i].u = u,e2[i].v = v,e2[i].l = l,e2[i].a = a;
add1(u,v,l,a),add1(v,u,l,a);
}
}
void dij(){
fo(i,1,n) q.push(make_pair(dis[i],i));
while(q.size()){
pair<int,int> x = q.top();
q.pop();
int u = x.second,l = x.first;
if(vis[u]) continue;
vis[u] = true;
for(node1 y:e1[u]){
int v = y.v,ll = y.l;
if(dis[v] > l+ll){
dis[v] = l+ll;
q.push(mp(dis[v],v));
}
}
}
}
void kruscal(){
cnt_point = n;
sort(e2+1,e2+1+m,cmp);
fo(i,1,m){
int u = e2[i].u;
int v = e2[i].v;
int a = e2[i].a;
int fu = getf(u),fv = getf(v);
if(fu == fv) continue;
cnt_point++;
fa[cnt_point] = fa[fu]+fa[fv];
fa[fu] = fa[fv] = cnt_point;
add3(fu,cnt_point),add3(cnt_point,fu);
add3(fv,cnt_point),add3(cnt_point,fv);
minv[cnt_point] = a;
mind[cnt_point] = inf;
}
fo(i,1,n)
minv[i] = inf,
mind[i] = dis[i];
}
void dfs(int now,int fa){
dep[now] = dep[fa]+1;
stp[now][0] = fa;
fo(i,1,19)
stp[now][i] = stp[stp[now][i-1]][i-1];
for(auto v:e3[now]){
if(v == fa) continue;
dfs(v,now);
mind[now] = min(mind[now],mind[v]);
}
}
void init(){
dij();
kruscal();
dfs(cnt_point,0);
}
int qq,k,s,st,p;
int query(int st,int p){
go(i,19,0){
if(dep[st] - (1<<i) > 0 and minv[stp[st][i]] > p)
st = stp[st][i];
}
return mind[st];
}
void solve(){
int lastans = 0;
cin>>qq>>k>>s;
while(qq--){
cin>>st>>p;
st = (st+k*lastans-1)%n + 1;
p = (p+k*lastans)%(s+1);
lastans = query(st,p);
cout<<lastans<<"\n";
}
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>T;
while(T--){
clear_data();
read();
init();
solve();
}
}