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

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

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

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

#include 
#include 
#include 
#include 

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 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;i2)
        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;
}

你可能感兴趣的:(欧拉回路)