CF512E. Cycling City

题目传送门

十分有趣的题。

思路

三条路径,本质上其实就是 \(x,y\) 同时属于两个有交集(至少交一条边)的简单环,这个肯定没问题。

套路的跑一遍 dfs,然后就有了返祖边树边和横叉边,然后朴素的分讨然后用个数据结构之类的维护一下就可以 \(n\log\) 解决了。

判有没有解倒是可以树上差分做,但这道题要求方案数,我们用一个暴力的思想,考虑每次对于一条非树边,我们暴力去覆盖树边,如果树边已经被覆盖,那么一定有解,取出这两条非树边然后去求答案即可。

具体求答案我简单叙述一下,具体还是自行画图看,首先把交集的点拿出来,然后按深度排序从小到大输出就完成了一部分。

然后对于 \(x,y\) 这条边,如果是横叉边,一定有一个点是结束点,然后输出就是形如 \(S,x,E\),其中 \(S,E\) 分别是开始点和结束点。否则是返祖边,那么假设 \(dep_x < dep_y\),那么就是 \(S,fa_S...,x,y,fa_y,...,E\),构造即可。

code

#include<bits/stdc++.h>
using namespace std;
#define int long long
namespace IO
{
	template<typename T>
	void read(T &_x){_x=0;int _f=1;char ch=getchar();while(!isdigit(ch)) _f=(ch=='-'?-1:_f),ch=getchar();while(isdigit(ch)) _x=_x*10+(ch^48),ch=getchar();_x*=_f;}
	template<typename T,typename... Args>
	void read(T &_x,Args&...others){Read(_x);Read(others...);}
	const int BUF=20000000;char buf[BUF],top,stk[32];int plen;
	#define pc(x) buf[plen++]=x
	#define flush(); fwrite(buf,1,plen,stdout),plen=0;
	template<typename T>inline void print(T x){if(!x){pc(48);return;}if(x<0) x=-x,pc('-');for(;x;x/=10) stk[++top]=48+x%10;while(top) pc(stk[top--]);}
}
using namespace IO;
const int N = 2e5+10;
int n,m,x,y,head[N],cnt,v[N],dep[N],son[N],op,fa[N],ly,ny,v1[N],v2[N],v3[N],len,len1,T[N],T1[N];
int X,Y,X1,Y1; 
struct w
{
	int to,nxt;
}b[N<<1];
inline void add(int x,int y)
{
	b[++cnt].nxt = head[x];
	b[cnt].to = y;
	head[x] = cnt;
}
void dfs(int x,int y)
{
	if(op == 1) return; 
	v[x] = 1,dep[x] = dep[y]+1; fa[x] = y;
	for(int i = head[x];i;i = b[i].nxt)
	{
		if(op == 1) return; 
		if(!v[b[i].to]) dfs(b[i].to,x);
		else if(b[i].to != y)//不是树边
		{
			if(dep[b[i].to] == dep[x])//横叉边
			{
				ly = x; ny = b[i].to;
				while(ly != ny)
				{//边转点 
					if(v1[ly])
					{
						X = x,Y = b[i].to;
						X1 = v1[ly],Y1 = v2[ly]; 
						op = 1;
						break;
					}
					if(v1[ny])
					{
						X = x,Y = b[i].to;
						X1 = v1[ny],Y1 = v2[ny]; 
						op = 1;
						break;
					}
					v1[ly] = x,v2[ly] = b[i].to;
					ly = fa[ly];
					v1[ny] = x,v2[ny] = b[i].to;
					ny = fa[ny];
				}
			}
			else if(dep[b[i].to] < dep[x])//返祖边
			{
				ly = x;
				while(ly != b[i].to)
				{//边转点 
					if(v1[ly])
					{
						X = x,Y = b[i].to;
						X1 = v1[ly],Y1 = v2[ly]; 
						op = 1;
						break;
					}
					v1[ly] = x,v2[ly] = b[i].to;
					ly = fa[ly];
				}
			}
		} 
	}
}
inline void C(int x,int y)//染色,注意这里是染点 
{
	if(dep[x] == dep[y])
	{
		ly = x,ny = y;
		while(ly != ny) v1[ny] = x,v2[ny] = y,v3[ly]++,v3[ny]++,ly++,ny++; 
		v3[ly]++;
	}
	else
	{
		ly = x;
		while(ly != y) v3[ly]++,ly = fa[ly];
		v3[ly]++;
	}
} 
inline bool cmp(int x,int y){ return dep[x] < dep[y]; }
inline void solve(int X,int Y)
{
	len1 = 0; ly = T[1]; T1[++len1] = ly;		
	if(dep[X] == dep[Y] && dep[Y] == ly) swap(X,Y);
	while(dep[Y] < dep[ly]) ly = fa[ly],T1[++len1] = ly;//S一直到Y去 
	if(dep[X] == dep[Y]) T1[++len1] = X,T1[++len1] = Y;//画图可以看出,这种一定是S->X->E这么连,dep相等一定有一个是E
	else 
	{
		T1[++len1] = X;
		while(X != T[len]) X = fa[X],T1[++len1] = X;//一直走到E为止 
	}
	print(len1),pc(' '); for(int i = 1;i <= len1;i++) print(T1[i]),pc(' '); pc('\n');
}
signed main()
{
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	read(n),read(m);
	for(int i = 1;i <= m;i++) read(x),read(y),add(x,y),add(y,x);
	//图不一定联通
	for(int i = 1;i <= n;i++)
		if(!v[i])
		{
			dfs(i,0);
			if(op)
			{
				pc('Y'),pc('E'),pc('S'),pc('\n');
				C(X,Y),C(X1,Y1);// cout<<X<<" * "<<Y<<" "<<X1<<" "<<Y1<<" "<<dep[X]<<" "<<dep[Y]<<" "<<dep[X1]<<" "<<dep[Y1]<<'\n';
				for(int i = 1;i <= n;i++)
					if(v3[i] == 2) T[++len] = i;
				sort(T+1,T+1+len,cmp);
				print(len),pc(' '); for(int i = 1;i <= len;i++) print(T[i]),pc(' '); pc('\n');
				solve(X,Y); solve(X1,Y1);
				flush();
				return 0;
			}
		}
	pc('N'),pc('O'),pc('\n');
	flush(); 
	return 0;
}
/*
10 20
5 1
10 5
2 10
6 4
10 6
9 6
1 7
3 10
3 2
6 2
5 4
7 10
3 9
9 1
5 3
7 9
8 4
4 7
6 3
10 8
注意到有三条路径
本质上就是有两个简单环交于同一条线段(交多部分也行)
考虑先跑dfs,这样只有返祖边,横叉边和树边
然后大致有四种情况
嗯,分别去看一下就好了,具体见代码
实现,emm目前我只会单log的,先写了来吧
我去我知道了,我们只需要看合不合法,然后构造任意一组方案
我们直接对于每条非树边暴力覆盖树边
然后有一条覆盖次数大于一那么一定有解了,输出
具体实现,请见代码 
*/
posted @ 2025-10-24 22:14  kkxacj  阅读(3)  评论(0)    收藏  举报