[NOI2018] 归程 题解

注意到题解区的解释好像都不清楚,错译我来写一篇。
首先建重构树,然后一个子树内的节点(根节点权值 \(\le p\))的点都可以到达。
答案就是这些点到点 \(1\) 的最短路的最小值。题解都没解释这是为什么。
注意到重构树的子树在原图上相当于一张导出子图,我们定义这张子图边上的点(即和不在这张子图内的点有连边)为特殊点,其他点离开子图都需要经过特殊点,所以答案即为特殊点的最短路最小值。

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int dis[400005] , f[400005] , len , n , m , fa[400005][31] , road[400005] , lastans , Q , k , maxhigh;
bool vis[400005]; 
struct tree{
	int val , fa , ls , rs;
}dots[400005];
struct edge{
	int to , nxt , val , high;
}ed[800005]; 
struct Edge{
	int u , v , w;
	bool operator < (const Edge &B)const{
		return w > B.w;
	}
}e[800005]; 
int head[400005] , edgecnt;
void add_edge(int u , int v , int w , int a){
	edgecnt++ , ed[edgecnt].to = v , ed[edgecnt].val = w , ed[edgecnt].high = a , ed[edgecnt].nxt = head[u];
	head[u] = edgecnt;
}
priority_queue<pair<int,int> > q;
void dijkstra(int s){
	memset(dis,0x3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	dis[s] = 0;
	q.push({0,s});
	while(!q.empty()){
		pair<int,int> p = q.top();q.pop();
		int u = p.second;
		if(vis[u])continue;
		vis[u] = 1;
		for(int i=head[u];i;i=ed[i].nxt){
			int v = ed[i].to;
			if(dis[v]>dis[u]+ed[i].val){
				dis[v] = dis[u] + ed[i].val;
				if(!vis[v])q.push({-dis[v],v});
			}
		}
	}
}
int find(int x){
	if(f[x]==x)return x;
	return f[x] = find(f[x]);
}
void kruskal(){
	len = n;
	sort(e+1,e+m+1);
	for(int i=1;i<=2*n;i++)f[i] = i , dots[i] = {0,0,0,0};
	for(int i=1;i<=m;i++){
		int u = find(e[i].u) , v = find(e[i].v) , w = e[i].w;
		if(u==v)continue;
		dots[++len] = {w,0,u,v};
		dots[u].fa = len , dots[v].fa = len;
        f[u] = len , f[v] = len;
	}
}
void dfs(int u){
	fa[u][0] = dots[u].fa , road[u] = dis[u];
	for(int j=1;j<30;j++)fa[u][j] = fa[fa[u][j-1]][j-1];
	if(dots[u].ls)dfs(dots[u].ls) , road[u] = min(road[u],road[dots[u].ls]);
	if(dots[u].rs)dfs(dots[u].rs) , road[u] = min(road[u],road[dots[u].rs]);
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
	int T;cin >> T;
	while(T--){
		edgecnt = 0 , lastans = 0;
		memset(head,0,sizeof(head)); 
		cin >> n >> m;
		for(int i=1;i<=m;i++){
			int u , v , l , a;cin >> u >> v >> l >> a;
			add_edge(u,v,l,a); 
			add_edge(v,u,l,a); 
			e[i] = {u,v,a};
		} 
		dijkstra(1);
		kruskal();
		dfs(len);
		cin >> Q >> k >> maxhigh;
		while(Q--){
			int v , p;cin >> v >> p;
			v = (v + k * lastans - 1) % n + 1 , p = (p + k * lastans) % (maxhigh + 1);
			for(int j=29;j>=0;j--){
				if(fa[v][j]!=0&&dots[fa[v][j]].val>p)v = fa[v][j]; 
			} 
			cout << (lastans = road[v]) << "\n"; 
		}
	}
	return 0;
}
posted @ 2026-06-13 16:55  虚空远行者  阅读(3)  评论(0)    收藏  举报