CP-library

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub Honam0905/CP-library

:heavy_check_mark: test/yosupo/Graph/eulerian_trail_directed.test.cpp

Depends on

Code

#define PROBLEM "https://judge.yosupo.jp/problem/eulerian_trail_directed"
#include "Misc/marco.hpp"
#include "Misc/debug.hpp"
const int INF=1e9;
const ll INFI=1e15;
//----------Author: Nguyen Ho Nam,UIT, Saigon-----------------
#include "Graph/Eulerian_trail.hpp"
int main(){
  int t; cin>>t;
  while(t--){
    int n,m; cin>>n>>m;
    eulerian_trail<int,true>et(n,m);
    rep(i,m){
        int u,v; cin>>u>>v;
        et.add_edge(u,v,i);
    }
     if(!et.get_trail()){
        cout<<"No"<<'\n';
     }else{
        cout<<"Yes"<<'\n';
        rep(i,(int)et.path.size()){
            cout<<et.path[i]<<(i+1<(int)et.path.size()?' ':'\n');
        }
        if(m==0){
            cout<<'\n';
        }else{
            For(i,1,(int)et.edge_path.size()){
                cout<<et.edge_path[i]<<(i+1<(int)et.edge_path.size()?' ':'\n');
            }
        }
     }
   }
}
#line 1 "test/yosupo/Graph/eulerian_trail_directed.test.cpp"
#define PROBLEM "https://judge.yosupo.jp/problem/eulerian_trail_directed"
#line 2 "Misc/marco.hpp"
// Judges with GCC >= 12 only needs Ofast
// #pragma GCC optimize("O3,no-stack-protector,fast-math,unroll-loops,tree-vectorize")
// MLE optimization
// #pragma GCC optimize("conserve-stack")
// Old judges
// #pragma GCC target("sse4.2,popcnt,lzcnt,abm,mmx,fma,bmi,bmi2")
// New judges. Test with assert(__builtin_cpu_supports("avx2"));
// #pragma GCC target("avx2,popcnt,lzcnt,abm,bmi,bmi2,fma,tune=native")
// Atcoder
// #pragma GCC target("avx2,popcnt,lzcnt,abm,bmi,bmi2,fma")
/*
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> ods;
- insert(x),erase(x)
- find_by_order(k): return iterator to the k-th smallest element
- order_of_key(x): the number of elements that are strictly smaller
*/
#include<bits/stdc++.h>
using namespace std;

using ld = long double;
using ll = long long;
using u32 = unsigned int;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using f128 = __float128;
 
 
#define pii pair<int,int>
#define pll pair<ll,ll>
 
#define all(x) (x).begin(),(x).end()
#define rall(x) (x).rbegin(),(x).rend()
#define ars(x) (x),(x+n)
 
#define TIME  (1.0 * clock() / CLOCKS_PER_SEC)
 
#define For(i,a,b) for (int i=(a); i<(b); i++)
#define rep(i,a) For(i,0,a)
#define rev(i,a,b) for (int i=(a); i>(b); i--)
#define FOR(i,a,b) for (int i=(a); i<=(b); i++)
#define REP(i,a) FOR(i,1,a)
#define REV(i,a,b) for (int i=(a); i>=(b); i--)
 
#define pb push_back
#define eb emplace_back
#define mp make_pair
#define fi first
#define se second
#define FT ios_base::sync_with_stdio(false); cin.tie(nullptr);
 
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

using vi=vector<int>;
using vll = vector<ll>;
template <class T>
using vc = vector<T>;
template <class T>
using vvc = vector<vc<T>>;
template <class T>
using vvvc = vector<vvc<T>>;
template <class T>
using vvvvc = vector<vvvc<T>>;
template <class T>
using vvvvvc = vector<vvvvc<T>>;
template <class T>
using pq = priority_queue<T>;
template <class T>
using pqg = priority_queue<T, vector<T>, greater<T>>;
 
#define vv(type, name, h, ...) \
  vector<vector<type>> name(h, vector<type>(__VA_ARGS__))
#define vvv(type, name, h, w, ...)   \
  vector<vector<vector<type>>> name( \
      h, vector<vector<type>>(w, vector<type>(__VA_ARGS__)))
#define vvvv(type, name, a, b, c, ...)       \
  vector<vector<vector<vector<type>>>> name( \
      a, vector<vector<vector<type>>>(       \
             b, vector<vector<type>>(c, vector<type>(__VA_ARGS__))))
 
//template <class T>
//using ods =
//   tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
 
template <typename T> bool chkmin(T &x,T y){return x>y?x=y,1:0;}
template <typename T> bool chkmax(T &x,T y){return x<y?x=y,1:0;}
 
template<class T> using pq = priority_queue<T>;
template<class T> using pqg = priority_queue<T, vector<T>, greater<T>>;
#line 1 "Misc/debug.hpp"
void __print(int x) {cerr << x;}
void __print(long x) {cerr << x;}
void __print(long long x) {cerr << x;}
void __print(unsigned x) {cerr << x;}
void __print(unsigned long x) {cerr << x;}
void __print(unsigned long long x) {cerr << x;}
void __print(float x) {cerr << x;}
void __print(double x) {cerr << x;}
void __print(long double x) {cerr << x;}
void __print(char x) {cerr << '\'' << x << '\'';}
void __print(const char *x) {cerr << '\"' << x << '\"';}
void __print(const string &x) {cerr << '\"' << x << '\"';}
void __print(bool x) {cerr << (x ? "true" : "false");}

template<typename T, typename V>
void __print(const pair<T, V> &x) {cerr << '{'; __print(x.first); cerr << ", "; __print(x.second); cerr << '}';}
template<typename T>
void __print(const T &x) {int f = 0; cerr << '{'; for (auto &i: x) cerr << (f++ ? ", " : ""), __print(i); cerr << "}";}
template<>
void __print(const vector<bool> &x) {int f = 0; cerr << '{'; for (size_t i = 0; i < x.size(); ++i) cerr << (f++ ? ", " : ""), __print(x[i]); cerr << "}";}
void _print() {cerr << "]\n";}
template <typename T, typename... V>
void _print(T t, V... v) {__print(t); if (sizeof...(v)) cerr << ", "; _print(v...);}

void dbg_out() { cerr << endl; }
template<typename Head, typename... Tail> void dbg_out(Head H, Tail... T) { __print(H); if (sizeof...(T)) cerr << ", "; dbg_out(T...); }
#define dbg(...) cerr << "[" << #__VA_ARGS__ << "]:"; dbg_out(__VA_ARGS__);
#line 4 "test/yosupo/Graph/eulerian_trail_directed.test.cpp"
const int INF=1e9;
const ll INFI=1e15;
//----------Author: Nguyen Ho Nam,UIT, Saigon-----------------
#line 2 "Graph/Eulerian_trail.hpp"
template<typename T,bool directed>
struct eulerian_trail {
    int n, m, E, ptr = 0;
    vector<int>head, link, to, eid, it_prev, it_cur;
    vector<bool>used;
    vector<T>path;
    vector<int>edge_path;

    eulerian_trail(int _n, int _m) : n(_n), m(_m) {
        E = directed ? m : 2*m;
        head.assign(n, 0);
        link.assign(E+1, 0);
        to.assign(E+1, 0);
        eid.assign(E+1, 0);
        used.assign(m, false);
        it_prev.assign(n, 0);
        it_cur.assign(n, 0);
    }

    void add_edge(int u, int v, int id) {
        auto ins = [&](int U, int V, int EID){
            int idx = ++ptr;
            to[idx] = V;
            eid[idx] = EID;
            int old = head[U];
            link[idx] = 0 ^ old;
            if(old) link[old] ^= 0 ^ idx;
            head[U] = idx;
        };
        if constexpr(directed) ins(u, v, id);
        else { ins(u, v, id); ins(v, u, id); }
    }

    bool is_eulerian() {
        if constexpr(directed) {
            int start=0, end=0;
            vector<int>in(n,0), out(n,0);
            for(int u=0; u<n; u++){
                int prev=0, cur=head[u];
                while(cur){
                    out[u]++; in[to[cur]]++;
                    int nxt = prev ^ link[cur];
                    prev = cur; cur = nxt;
                }
            }
            for(int i=0;i<n;i++){
                int d = out[i] - in[i];
                if(d==1) start++;
                else if(d==-1) end++;
                else if(d!=0) return false;
            }
            return (start==1&&end==1) || (start==0&&end==0);
        } else {
            int odd=0;
            for(int u=0;u<n;u++){
                int deg=0, prev=0, cur=head[u];
                while(cur){
                    deg++;
                    int nxt = prev ^ link[cur];
                    prev = cur; cur = nxt;
                }
                if(deg%2) odd++;
                if(odd>2) return false;
            }
            return odd==0 || odd==2;
        }
    }

    T find_start() {
        if constexpr(directed) {
            vector<int>in(n,0), out(n,0);
            for(int u=0;u<n;u++){
                int prev=0, cur=head[u];
                while(cur){
                    out[u]++; in[to[cur]]++;
                    int nxt=prev^link[cur];
                    prev=cur; cur=nxt;
                }
            }
            for(int i=0;i<n;i++)
                if(out[i]-in[i]==1) return i;
            for(int i=0;i<n;i++)
                if(out[i]>0) return i;
            return 0;
        } else {
            for(int u=0;u<n;u++){
                int deg=0, prev=0, cur=head[u];
                while(cur){
                    deg++;
                    int nxt=prev^link[cur];
                    prev=cur; cur=nxt;
                }
                if(deg%2==1) return u;
            }
            for(int u=0;u<n;u++)
                if(head[u]!=0) return u;
            return 0;
        }
    }

    bool get_trail(){
        if(!is_eulerian()) return false;
        for(int u=0;u<n;u++){
            it_prev[u]=0;
            it_cur[u]=head[u];
        }
        stack<pair<T,int>>st;
        st.emplace(find_start(), -1);
        while(!st.empty()){
            auto [u, in_eid]=st.top();
            int &prev=it_prev[u];
            int &cur=it_cur[u];
            while(cur){
                int idx=cur;
                int nxt=prev^link[idx];
                prev=idx;
                cur=nxt;
                int e=eid[idx];
                if(!used[e]){
                    used[e]=true;
                    st.emplace(to[idx], e);
                    goto CONTINUE;
                }
            }
            path.push_back(u);
            edge_path.push_back(in_eid);
            st.pop();
            CONTINUE: ;
        }
        if((int)path.size()!=m+1)
            return false;
        reverse(path.begin(),path.end());
        reverse(edge_path.begin(),edge_path.end());
        return true;
    }
};
#line 8 "test/yosupo/Graph/eulerian_trail_directed.test.cpp"
int main(){
  int t; cin>>t;
  while(t--){
    int n,m; cin>>n>>m;
    eulerian_trail<int,true>et(n,m);
    rep(i,m){
        int u,v; cin>>u>>v;
        et.add_edge(u,v,i);
    }
     if(!et.get_trail()){
        cout<<"No"<<'\n';
     }else{
        cout<<"Yes"<<'\n';
        rep(i,(int)et.path.size()){
            cout<<et.path[i]<<(i+1<(int)et.path.size()?' ':'\n');
        }
        if(m==0){
            cout<<'\n';
        }else{
            For(i,1,(int)et.edge_path.size()){
                cout<<et.edge_path[i]<<(i+1<(int)et.edge_path.size()?' ':'\n');
            }
        }
     }
   }
}
Back to top page