【题解】P4768 [NOI2018] 归程
一:【题意】
一张 \(n\) 个点 \(m\) 条边的图。每条边有长度和海拔。
\(q\) 次询问,每次给你起点 \(v\) 和海拔 \(p\),你可以先乘车到一个点然后步行到 \(1\) 。
乘车只能通过海拔 \(>p\) 的边。
最小化步行到 \(1\) 的距离。
二:【解法】
跑 \(dijkstra\) 求 \(1\) 到每个点 \(x\) 的最短路 \(dis\)
求一个点乘车可到的点,然后对 \(dis\) 取最小值
求一个点只走 \(>p\) 的边可到的点集,是 \(kruskal\) 重构树的经典应用
所以我们建 \(kruskal\) 重构树,对某个子树 \(dis\) 取 \(min\) 即可
三:【代码】
#include<bits/stdc++.h>
#define Pair pair<int,int>
#define w first
#define v second
#define inf 2e9+10
using namespace std;
const int N=4e5+10;int n;
struct Edge{
int u,v,w,h;
}edg[N];
vector<Pair> mp[N];
int dis[N],vis[N];
void Dijkstra(){
for(int i=0;i<N;i++) dis[i]=inf;
for(int i=0;i<N;i++) vis[i]=0;
priority_queue<Pair,vector<Pair>,greater<Pair> > q;
q.push({0,1});dis[1]=0;
while(q.size()){
int u=q.top().v;q.pop();
if(vis[u]) continue;
vis[u]=1;
for(auto e:mp[u]){
int v=e.v,w=e.w;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
q.push({dis[v],v});
}
}
}
}
bool cmp(Edge a,Edge b){
return a.h>b.h;
}
int bcj[N];
int find(int x){
if(x==bcj[x]) return x;
return bcj[x]=find(bcj[x]);
}
int nw[N],fa[20][N];
vector<int> sq[N];
int as[N];
void dfs(int u,int pa){
fa[0][u]=pa;
as[u]=dis[u];
for(auto v:sq[u]){
if(v==pa) continue;
dfs(v,u);
as[u]=min(as[u],as[v]);
}
}
void clears(){
for(int i=0;i<N;i++){
mp[i].clear();
sq[i].clear();
}
}
void solve(){
int m;cin>>n>>m;
clears();
for(int i=1;i<=m;i++){
int u,v,w,h;cin>>u>>v>>w>>h;
edg[i]={u,v,w,h};
mp[u].push_back({w,v});
mp[v].push_back({w,u});
}
Dijkstra();
sort(edg+1,edg+1+m,cmp);
for(int i=1;i<=2*n;i++) bcj[i]=i;
int cnt=n;
for(int i=1;i<=n;i++) nw[i]=inf;
for(int i=1;i<=m;i++){
int u=edg[i].u,v=edg[i].v,w=edg[i].h;
u=find(u);v=find(v);
if(u==v) continue;
cnt++;
sq[cnt].push_back(u);
sq[cnt].push_back(v);
nw[cnt]=w;
bcj[u]=bcj[v]=cnt;
}
dfs(cnt,0);
//for(int i=1;i<=cnt;i++) cout<<as[i]<<" ";cout<<"\n";
for(int k=1;k<20;k++){
for(int i=1;i<=cnt;i++) fa[k][i]=fa[k-1][fa[k-1][i]];
}
int q,K,S;cin>>q>>K>>S;
int ans=0;
while(q--){
int x,down;cin>>x>>down;
x=(x+K*ans-1)%n+1;
down=(down+K*ans)%(S+1);
for(int i=19;i>=0;i--){
if(fa[i][x]&&nw[fa[i][x]]>down) x=fa[i][x];
}
ans=as[x];
cout<<ans<<"\n";
}
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int t;cin>>t;
while(t--) solve();
return 0;
}

浙公网安备 33010602011771号