[欧拉回路] 「Balkan OI 2016」Acrobat

来源:互联网 发布:java 计算两个时间差 编辑:程序博客网 时间:2024/06/07 02:24

一个图是欧拉图的充要条件是每个点度数是偶数且连通

第一种操作是同时更改 aiaj 的度数奇偶性,那么 aiaj 之间连边,搞棵生成树,一个点的度数是奇数时就删去它与它父亲的边。

然后用第二种操作把左边的点连通,再用第二种操作把左边度数为奇数的点连起来

#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;}