【转载自我的洛谷博客】欧拉路、欧拉回路学习笔记
https://www.luogu.com.cn/blog/300078/ou-la-lu-ou-la-hui-lu-xue-xi-bi-ji
In Addition
【例】C. Johnny and Megan's Necklace
欧拉回路的建模是思维的一个难点。本题为典型的欧拉回路与二进制表示结合的题目。题解:考虑枚举 \(b\),那么就需要保证beauty都不低于 \(b\),即两个权值为 \(u,v\) 的节点可以相连等价于 \(u\&(2^b-1)=v\&(2^b-1)\)。图论建模,对每个部件\((p,q)\)在一张图上的 \(p\&(2^b-1),q\&(2^b-1)\) 两点间连双向边,在此得到了一张节点为 \(0\sim 2^b-1\)、共 \(n\) 条边的图,那么 \(b\) 是可以的当且仅当这是一张欧拉图。注意欧拉图可以有大小为1的连通块散落在旁。
评:可以积累套路
#include <bits/stdc++.h>
using namespace std;
const int N=2e6+5;
int n,tp,p,a[N],deg[N],ans[N],vis[N];
vector<pair<int,int> >G[N];
pair<int,int>stk[N];
void dfs(int s){
stk[++tp]=make_pair(s,0);
while(tp){
int x=stk[tp].first,z=stk[tp].second;
while(G[x].size()&&vis[abs(G[x].back().second)])G[x].pop_back();
if(!G[x].size())ans[++p]=z,tp--;
else {
vis[abs(G[x].back().second)]=1;
stk[++tp]=G[x].back();
}
}
}
int main(){
cin>>n;
for(int i=1;i<=2*n;i++)cin>>a[i];
for(int b=20;~b;b--){
p=0,memset(vis,0,sizeof(vis)),memset(deg,0,sizeof(deg));
for(int i=0;i<(1<<b);i++)G[i].clear();
for(int i=2;i<=2*n;i+=2){
int u=a[i]&((1<<b)-1),v=a[i-1]&((1<<b)-1);
G[u].push_back(make_pair(v,i/2)),G[v].push_back(make_pair(u,-i/2));
deg[u]++,deg[v]++;
}
bool flag=1;
for(int i=0;i<(1<<b);i++)if(deg[i]&1){flag=0;break;}
if(!flag)continue;
for(int i=0;i<(1<<b)&&p<2;i++)p=0,dfs(i);
if(p!=n+1)continue;
cout<<b<<'\n';
for(int i=p-1;i;i--)
if(ans[i]>0)cout<<ans[i]*2<<' '<<ans[i]*2-1<<' ';
else cout<<-1-ans[i]*2<<' '<<ans[i]*-2<<' ';
break;
}
}