#Kruskal重构树,Dijkstra,倍增#洛谷 4768 [NOI2018]归程
分析
首先Dijkstra是必需的(关于SPFA,它死了233)
无向图,所以先求出1号节点到所有点的距离,然后肯定希望起点能驾驶到离一号点最短的汽车可到的地方
但是怎么办,考虑海拔大的边肯定会更想选,那为什么不用Kruskal建出一棵最大生成树
但是怎么求呢,Kruskal重构树横空出世,通过用新点连接原来两点,建起一棵\(2n-1\)个点的树
那有什么用呢,这棵树变成了二叉堆,在本题中还是小根堆,也就是两点LCA代表了重构树路径上最小边
那边再求个最小值不就可以用倍增解决了吗
代码
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define rr register
using namespace std;
const int N=400011;
struct rec{int x,y,w,c;}T[N]; struct node{int y,w,next;}e[N<<1]; struct Node{int y,next;}E[N];
int ls[N>>1],hs[N],dis[N],h[N],dep[N],n,m,k,K,cnt,nnt,f[N][20],Q,opt,S,fat[N]; pair<int,int>heap[N>>1];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+c-48,c=getchar();
return ans;
}
inline void add(int x,int y,int w){e[++k]=(node){y,w,ls[x]}; ls[x]=k;}
inline void Add(int x,int y){E[++K]=(Node){y,hs[x]},hs[x]=K;}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline void Push(pair<int,int>w){
heap[++cnt]=w;
rr int x=cnt;
while (x>1){
if (heap[x>>1]>heap[x])
swap(heap[x>>1],heap[x]),x>>=1;
else return;
}
}
inline void Pop(){
heap[1]=heap[cnt--];
rr int x=1;
while ((x<<1)<=cnt){
rr int y=x<<1;
if (y<cnt&&heap[y+1]<heap[y]) ++y;
if (heap[y]<heap[x]) swap(heap[y],heap[x]),x=y;
else return;
}
}
inline void Dijkstra(){
dis[1]=0,heap[++cnt]=make_pair(0,1);
while (cnt){
rr int x=heap[1].second,t=heap[1].first;
Pop(); if (t!=dis[x]) continue;
for (rr int i=ls[x];i;i=e[i].next)
if (dis[e[i].y]>dis[x]+e[i].w){
dis[e[i].y]=dis[x]+e[i].w;
Push(make_pair(dis[e[i].y],e[i].y));
}
}
}
bool cmp(rec x,rec y){return x.c>y.c;}
inline signed getf(int u){return fat[u]==u?u:fat[u]=getf(fat[u]);}
inline void Kruskal(){
for (rr int i=1;i<n*2;++i) fat[i]=i;
for (rr int i=1,tot=0;i<=m;++i){
rr int fa=getf(T[i].x),fb=getf(T[i].y);
if (fa!=fb){
fat[fa]=fat[fb]=++nnt,h[nnt]=T[i].c;
Add(nnt,fa),Add(nnt,fb);
if (++tot==n-1) return;
}
}
}
inline void dfs(int x,int fa){
dep[x]=dep[fa]+1,f[x][0]=fa;
for (rr int i=1;i<20;++i) f[x][i]=f[f[x][i-1]][i-1];
for (rr int i=hs[x];i;i=E[i].next)
dfs(E[i].y,x),dis[x]=min(dis[x],dis[E[i].y]);
}
inline signed GetF(int x,int H){
for (rr int i=19;~i;--i)
if (dep[x]>=(1<<i)&&h[f[x][i]]>H) x=f[x][i];
return dis[x];
}
signed main(){
for (rr int Test=iut();Test;--Test){
memset(ls,0,sizeof(ls)),memset(f,0,sizeof(f));
memset(dep,0,sizeof(dep)),memset(hs,0,sizeof(hs));
memset(h,0,sizeof(h)),memset(dis,0x3f,sizeof(dis));
n=iut(),m=iut(),k=K=1,nnt=n;
for (rr int i=1;i<=m;++i){
T[i]=(rec){iut(),iut(),iut(),iut()};
add(T[i].x,T[i].y,T[i].w);
add(T[i].y,T[i].x,T[i].w);
}
Dijkstra(),sort(T+1,T+1+m,cmp),Kruskal(),
dfs(nnt,0),Q=iut(),opt=iut(),S=iut();
for (rr int lastans=0;Q;Q--){
rr int G=iut(),H=iut();
if (opt) G=(G+lastans-1)%n+1,H=(H+lastans)%(S+1);
print(lastans=GetF(G,H)),putchar(10);
}
}
return 0;
}