一个图是欧拉图的充要条件是每个点度数是偶数且连通
第一种操作是同时更改 ai 与 aj 的度数奇偶性,那么 ai 与 aj 之间连边,搞棵生成树,一个点的度数是奇数时就删去它与它父亲的边。
然后用第二种操作把左边的点连通,再用第二种操作把左边度数为奇数的点连起来
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int N=600010;
int n,m,cnt;
int a[N],b[N],du[N],G[N],vis[N],pkd[N];
struct edge{
int t,nx;
}E[N];
struct tpl{
int opt,x,y;
};
vector<tpl> ans;
inline void addedge(int x,int y){
E[++cnt].t=y; E[cnt].nx=G[x]; G[x]=cnt;
E[++cnt].t=x; E[cnt].nx=G[y]; G[y]=cnt;
}
void dfs(int u){
vis[u]=1;
for(int i=G[u];i;i=E[i].nx)
if(!vis[E[i].t]){
dfs(E[i].t);
if(du[E[i].t]){
pkd[i+1>>1]=1;
du[u]^=1; du[E[i].t]^=1;
}
}
}
int fa[N];
int find(int x){
return x==fa[x]?x:fa[x]=find(fa[x]);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d",&a[i],&b[i]);
addedge(a[i],b[i]);
du[a[i]]^=1; du[b[i]+n]^=1;
}
for(int i=1;i<=n;i++)
if(!vis[i]){
dfs(i);
if(du[i]) return puts("-1"),0;
}
for(int i=1;i<=m;i++)
if(pkd[i]){
du[b[i]+n]^=1,du[a[i]+n]^=1;
ans.push_back({1,a[i],b[i]});
swap(a[i],b[i]);
}
for(int i=1;i<=2*n;i++) fa[i]=i;
for(int i=1;i<=m;i++) fa[find(a[i])]=find(b[i]);
for(int i=2;i<=n;i++)
if(find(n+i)!=find(n+i-1)){
ans.push_back({2,i-1,i}); fa[find(n+i)]=find(n+i-1);
du[n+i]^=1; du[n+i-1]^=1;
}
vector<int> iodd;
for(int i=1;i<=n;i++)
if(du[i+n]) iodd.push_back(i);
if(iodd.size()&1) return puts("-1"),0;
for(int i=0;i<iodd.size();i+=2)
ans.push_back({2,iodd[i],iodd[i+1]});
printf("%d\n",ans.size());
for(auto i : ans) printf("%d %d %d\n",i.opt,i.x,i.y);
return 0;
}