题解:P17122 [ICPC 2025 Shanghai R] Hamu
lailai0916 · · 题解
题意简述
给定无向多重图与起点
解题思路
只需保留每个
游走始终位于
再考虑连通块内目标奇偶向量中
若目标向量中有奇数个
设找到的同色边为
先考虑生成树的标准环游:从
按照广度优先顺序的逆序处理每个非根结点
相较于标准环游,这两步会分别多到达父亲和
根结点也必然正确。翻转奇环后,目标向量中有偶数个
最后再次非递归遍历生成树,依次输出标准环游,并在对应结点离开前插入已经确定的折返。若使用了奇环,就在路线第一次到达
奇环长度至多为
广度优先搜索、奇环恢复与路线构造都只线性处理结点和边。时间复杂度为
正确性证明
若目标为奇的城市不在
连接同色结点的边与树上路径长度奇偶相同,再加一条边后得到奇环。沿该环一周会把环上每个城市的到达奇偶性翻转一次,使目标向量中
在生成树环游中,额外折返
奇环和所有树上动作都沿输入道路移动,拼接点也与当前所在城市一致,故输出始终是一条从 Yes,给出的路线就满足全部要求;结合无解条件,算法正确。
参考代码
#include <bits/stdc++.h>
using namespace std;
const int N=200005;
int a[N],fa[N],dep[N],col[N];
bool cur[N],add[N];
vector<int>G[N],son[N];
int lca(int x,int y)
{
while(dep[x]>dep[y])x=fa[x];
while(dep[y]>dep[x])y=fa[y];
while(x!=y)
{
x=fa[x];
y=fa[y];
}
return x;
}
vector<int> get_cycle(int x,int y)
{
if(x==y)return {x};
int z=lca(x,y);
vector<int>res={y},p;
for(int i=y;i!=z;i=fa[i])res.push_back(fa[i]);
for(int i=x;i!=z;i=fa[i])p.push_back(i);
reverse(p.begin(),p.end());
for(auto i:p)res.push_back(i);
return res;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin>>T;
while(T--)
{
int n,m,s;
cin>>n>>m>>s;
for(int i=1;i<=n;i++)
{
G[i].clear();
son[i].clear();
fa[i]=-1;
cin>>a[i];
a[i]&=1;
}
for(int i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;
G[x].push_back(y);
G[y].push_back(x);
}
vector<int>ord;
queue<int>que;
int u=0,v=0;
fa[s]=0;
dep[s]=col[s]=0;
ord.push_back(s);
que.push(s);
while(que.size())
{
int x=que.front();
que.pop();
for(auto y:G[x])
{
if(fa[y]==-1)
{
fa[y]=x;
dep[y]=dep[x]+1;
col[y]=col[x]^1;
son[x].push_back(y);
ord.push_back(y);
que.push(y);
}
else if(!u&&col[x]==col[y])
{
u=x;
v=y;
}
}
}
bool ok=1;
int sum=0;
for(int i=1;i<=n;i++)
{
if(a[i]&&fa[i]==-1)ok=0;
if(a[i]&&fa[i]!=-1)sum^=1;
}
vector<int>cyc;
if(ok&&sum)
{
if(!u)ok=0;
else
{
cyc=get_cycle(u,v);
for(auto x:cyc)a[x]^=1;
}
}
if(!ok)
{
cout<<"No"<<'\n';
continue;
}
for(auto x:ord)
{
cur[x]=x!=s;
add[x]=0;
}
for(int i=1;i<ord.size();i++)cur[fa[ord[i]]]^=1;
for(int i=ord.size()-1;i>=1;i--)
{
int x=ord[i];
if(cur[x]!=a[x])
{
add[x]=1;
cur[x]^=1;
cur[fa[x]]^=1;
}
}
vector<int>ans;
vector<pair<int,int>>st={{s,0}};
bool used=cyc.empty();
while(st.size())
{
int x=st.back().first;
if(!used&&x==u)
{
for(auto y:cyc)ans.push_back(y);
used=1;
}
if(st.back().second<son[x].size())
{
int y=son[x][st.back().second++];
ans.push_back(y);
st.push_back({y,0});
}
else
{
st.pop_back();
if(x==s)continue;
if(add[x])
{
ans.push_back(fa[x]);
ans.push_back(x);
}
ans.push_back(fa[x]);
}
}
cout<<"Yes"<<'\n'<<ans.size()<<'\n';
for(auto x:ans)cout<<x<<' ';
cout<<'\n';
}
return 0;
}