Live2D

【NOIP2018】旅行

一句话题意:
从一号点,可以回溯,但不能重新经过之前经过的节点
问走完所有点,最后走到n,走出的节点序的字典序最小是多少

由于图可能是一棵树或者一棵基环树,所以重点基本都在基环树上

NOIP的D2T1的原数据范围还是很小的,直接枚举环上断每一条边的最小答案即可

然而cz搞了一个数据加强版,显而易见就只能用\(\Theta(n\log n)\)的复杂度跑了

具体的方式是:走到环的入口的时候,判断一下节点大小关系,分情况讨论

这样可以避免很多无脑断边的情况

代码:

#include<bits/stdc++.h>
#define N 500005
using namespace std;

int n,m,u,v;

struct Edge
{
	int next,to;
}edge[N<<1];
int cnt=0,head[N];

inline void add_edge(int from,int to)
{
	edge[++cnt].next=head[from];
	edge[cnt].to=to;
	head[from]=cnt;
}

template<class T>inline void read(T &res)
{
	char c;T flag=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
	while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}

bool book[N],cir[N],hav;
int fa[N];
void dfs1(int u,int fa)
{
	book[u]=1;
	for(register int i=head[u];i;i=edge[i].next)
	{
		int v=edge[i].to;
		if(v==fa) continue;
		if(book[v])
		{
			hav=cir[u]=cir[v]=1;
			return;
		}
		dfs1(v,u);
		if(hav&&cir[v])
		{
			if(cir[u]) hav=0;
			cir[u]=1;
			return;
		}
	}
}

queue<int> ans;
void dfs2(int u,int pos)
{
	if(book[u]) return;
	book[u]=1;
	ans.push(u);
	priority_queue<int,vector<int>,greater<int> > qq;
	for(register int i=head[u];i;i=edge[i].next)
	{
		int v=edge[i].to;
		if(v==fa[u]) continue;
		if(book[v]) continue;
		qq.push(v);
	}
	while(!qq.empty())
	{
		int now=qq.top();
		qq.pop();
		if(!hav&&cir[now]&&now>pos&&qq.empty())
		{
			hav=1;
			return;
		}
		int nxt=-0x3f3f3f3f;
		if(!qq.empty()&&cir[u]) nxt=qq.top();
		if(nxt==-0x3f3f3f3f) nxt=pos;
		dfs2(now,nxt);
	}
}

int main()
{
	read(n);read(m);
	for(register int i=1;i<=m;++i)
	{
		read(u);read(v);
		add_edge(u,v);
		add_edge(v,u);
	}
	dfs1(1,1);
	memset(book,0,sizeof(book));
	hav=0;
	dfs2(1,0x3f3f3f3f);
	while(!ans.empty())
	{
		printf("%d ",ans.front());
		ans.pop();
	}
	return 0;
}

/*
6 6
1 2
2 3
2 4
2 5
3 6
4 6
*/

另外,这份代码好像有点问题,因为之前脑子一抽设的fa数组根本没更新
后面dfs2还用到了……
但是影响不大,还是可以A

posted @ 2019-11-04 20:53  tqr06  阅读(104)  评论(0编辑  收藏  举报