题解:[NOIP 2018 提高组] 旅行 加强版

题目传送门

题意分析

旅行原题中是 \(\mathcal O\left(n^2\right)\) 的,但是加强版中 \(n\leq500000\),因此需要优化。

对于 \(m=n-1\) 的情况,可以直接 DFS 一遍求得答案。

但是对于 \(m=n\) 的情况,原题是 \(\mathcal O(m)\) 枚举断边,因此效率低下。

考虑如何快速确定环上的边应不应该断。

令断边为 \((u,v)\)

\(f_u,u,v\) 均在环上,否则会不连通;其中 \(f_u\) 表示节点 \(u\) 的父节点。

还需满足:

  • \(v\)\(u\) 最大的子节点,否则字典序一定更劣。

  • \(v>\textit{}nxt\),其中 \(\textit{nxt}\) 表示从点 \(u\) 向上回溯后,访问的第一个新节点

    否则字典序一定更劣。

搞清楚这三个条件后,题目便很简单了。

对于实现,可以将 \(f_x\)\(x\) 的邻接表里删除,便于寻找最大子节点。

可以将 \(\textit{nxt}\) 作为 DFS 的参数传递。

AC 代码

时间复杂度:\(\mathcal O(n\log n)\)

其瓶颈其实在于给边排序,可以使用基数排序做到 \(\mathcal O(n)\)

//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
constexpr const int N=500000,M=N;
int n,m;
vector<int>g[N+1];
int ans[N+1],size;
bool flag=false;
void dfs(int x,int fx){
	ans[++size]=x;
	for(int &i:g[x]){
		if(i==fx){
			continue;
		}
		dfs(i,x);
	}
}
vector<int>ring;
bool inRing[N+1];
bool findRing(int x,int fx){
	static int flag[N+1];
	static vector<int>s;
	if(flag[x]){
		for(int i=s.size()-1;i>=flag[x];i--){
			ring.push_back(s[i]);
			inRing[s[i]]=true;
		}
		return true;
	}
	flag[x]=s.size();
	s.push_back(x);
	for(int i:g[x]){
		if(i==fx){
			continue;
		}
		if(findRing(i,x)){
			return true;
		}
	}
	flag[x]=0;
	s.pop_back();
	return false;
}
bool returned;
bool vis[N+1];
void dfs2(int x,int fx,int nxt){
//	cerr<<"dfs2("<<x<<","<<fx<<","<<nxt<<")\n";
	//删除父节点,便于处理 
	if(fx){
		g[x].erase(lower_bound(g[x].begin(),g[x].end(),fx));
	} 
	ans[++size]=x;
	vis[x]=true;
	//可能需要回溯(不走环上点)
	if(!returned && inRing[fx] && inRing[x] && inRing[g[x].back()] && g[x].back() > nxt){
		returned=true;
		for(int i=0;i<g[x].size()-1;i++){
			if(/*g[x][i]==fx||*/vis[g[x][i]]){
				continue;
			}
			if(i+1<g[x].size()-1){
				dfs2(g[x][i],x,g[x][i+1]);
			}else{
				dfs2(g[x][i],x,nxt);
			}
		}
	}else{
		for(int i=0;i<g[x].size();i++){
			if(/*g[x][i]==fx||*/vis[g[x][i]]){
				continue;
			}
			if(i+1<g[x].size()){
				dfs2(g[x][i],x,g[x][i+1]);
			}else{
				dfs2(g[x][i],x,nxt);
			}
		}
	}
}
int main(){
	/*freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);*/
	
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int u,v;
		cin>>u>>v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	for(int i=1;i<=n;i++){
		sort(g[i].begin(),g[i].end());
	}
	if(m==n-1){
		dfs(1,0);
	}else{
		findRing(1,0);
		dfs2(1,0,N+1);
	}
	for(int i=1;i<=n;i++){
		cout<<ans[i]<<' ';
	}
	cout<<'\n';
	
	cout.flush();
	
	/*fclose(stdin);
	fclose(stdout);*/
	return 0;
}
/*
10 10
10 7
9 4
10 4
10 3
6 10
9 8
3 8
5 8
2 6
10 1

1 10 3 4 9 8 5 6 2 7
*/
posted @ 2025-07-22 17:46  TH911  阅读(6)  评论(0)    收藏  举报