//#include <bits/stdc++.h>
//#include <time.h>
//#define fi first
//#define se second
//#define endll "\n"
//#define MS0(X) memset((X), 0, sizeof((X)))
//#define MS1(X) memset((X), -1, sizeof((X)))
//#define LEN(X) strlen(X)
//#define rg(a,x,y) (a+x), (a+y+1)
//#define vrg(a,x,y) (a.begin()+x),(a.begin()+y+1)
//#define all(x) (x).begin(),(x).end()
//#define rall(x) (x).rbegin(),(x).rend()
//#define _sum(a) accumulate(a, 0ll)
//#define _max(a,b) *max_element(a,b)
//#define pb push_back
//#define pr make_pair
//#define bugc(_) cerr << (#_) << " = " << (_) << endl;
//#define sz(x) ((int)x.size())
//#define L(i,u) for (register int i=head[u]; i; i=nxt[i])
//#define fr1(i,a,b) for (register int i=(a); i<=(b); i++)
//#define fr2(i,a,b) for (register int i=(a); i>=(b); i--)
//#define ios  ios::sync_with_stdio(false);
//#define lson l,mid,rt << 1
//#define rson mid + 1,r,rt << 1 | 1
/////vector(len,val);
//using namespace std;
//
//typedef long long ll;
//typedef double db;
//int xx[4] = {1,-1,0,0};
//int yy[4] = {0,0,1,-1};
//const double eps = 1e-9;
//typedef pair<int,int>  P;
//typedef pair<ll,ll>  Pl;
//typedef pair<double,double>  PP;
//const int maxn = 2e6 + 5000;
//const ll mod = 1e9 + 7;
//const int INF(0x3f3f3f3f);
//const ll INFL(0x3f3f3f3f3f3f3f3fll);
//inline int sign(db a) { return a < -eps ? -1 : a > eps;}
////inline int cmp(db a,db b){ return sign(a - b);}
//
//ll mul(ll a,ll b,ll c) { ll res = 1; while(b) {  if(b & 1) res *= a,res %= c;  a *= a,a %= c,b >>= 1;  }  return res;}
//ll mulll(ll a,ll b,ll c) { ll res = 1; while(b) {  if(b & 1) res *= a,res %= c;  a *= a,a %= c,b >>= 1;  }  return res;}
//ll phi(ll x) {  ll res = x;  for(ll i = 2; i * i <= x; i++) { if(x % i == 0) res = res / i * (i - 1);   while(x % i == 0) x /= i;   }  if(x > 1) res = res / x  * (x - 1);    return res;}
//template <typename A, typename B> inline bool chmin(A &a, B b){if(a > b) {a = b; return 1;} return 0;}
//template <typename A, typename B> inline bool chmax(A &a, B b){if(a < b) {a = b; return 1;} return 0;}
//template <typename A, typename B> inline ll add(A x, B y) {if(x + y < 0) return x + y + mod; return x + y >= mod ? x + y - mod : x + y;}
//template <typename A, typename B> inline void add2(A &x, B y) {if(x + y < 0) x = x + y + mod; else x = (x + y >= mod ? x + y - mod : x + y);}
//template <typename A, typename B> inline ll mul1(A x, B y) {return 1ll * x * y % mod;} /// x * y % mod;
//template <typename A, typename B> inline void mul2(A &x, B y) {x = (1ll * x * y % mod + mod) % mod;} /// return x * y
//template <typename A> inline void debug(A a){cout << a << '\n';}
//template <typename A> inline ll sqr(A x){return 1ll * x * x;}
//template <typename A> A inv(A x) {return mulll(x, mod - 2,mod);}
//template <typename A> void bugl(A a[],int l,int r) { for(int i = l;i <= r;i++) cout << a[i] << " "; cout << endl;  }
//template <typename A> void bug(A a[],int l,int r) { for(int i = l;i <= r;i++) cout << a[i] << " "; cout << endl;  }
//template<class T>void wt(const T& x){cout << x << endl;}
//template<class T>void wt(const T& x, char c){cout << x << c;}
//template<class T>void wt(const T& x, const string& s){cout << x << s;}
//template<class T>void wt(const T& x, int rnd){  cout << fixed << setprecision(rnd) << x << endl;}
//template<class T> inline void read(T &x){  x=0; char c=getchar(); int f=1;  while (!isdigit(c)) {if (c=='-') f=-1; c=getchar();} while (isdigit(c)) {x=x*10+c-'0'; c=getchar();} x*=f;}
//inline ll lowbit(ll x){ return (x & (-x)); }
//inline void debug(){  cout << "###!!!" << endl;}
////inline void bugl(int a[],int l,int r){ for(int i = l;i <= r;i++) cout << a[i] << " "; cout << endl; }
////inline void bug(int a[],int l,int r){ for(int i = l;i <= r;i++) cout << a[i] << " ";  }
// ll n;
//Pl p[maxn];
//bool cmp(P a,P b) {
//    return a.fi - a.se >= b.fi - b.se;
//}
//ll op[33];
//ll l[maxn];
//int main() {
//    int t;
//    op[1] = 1;
//    for(int i = 2;i <= 20;i++) op[i] = op[i - 1] * 2;
//    cin >> t;
//    while(t--) {
//        string str;
//        cin >> str; ll ans = 0; int id = 0;
//        for(int i = 0;i < str.size();i++){
//                l[i] = 0;   if(str[i] == '1') l[i] = id,id = i;
//        }
//        for(int i = str.size() - 1;i >= 0;i--){
//            ll val = 0,cnt = 1;
//            if(str[i] == '1') val += 1,ans++;
//            for(int j = i - 1,k = 0;j >= 0 && k <= 20;k++,j--){
//                cnt++;
//                if(str[j] == '1') val += op[cnt];
//                if(val > cnt){
//                    int cha = val - cnt;
//                    if(l[j] - j - 1 >= cha)ans++;
//                }
//                if(val == cnt) ans++;
//            }
//            bugc(ans);
//        } wt(ans);
//    }
//    return 0;
//}
//
//

#include <bits/stdc++.h>
#include <time.h>
#define fi first
#define se second
#define endll "\n"
#define MS0(X) memset((X), 0, sizeof((X)))
#define MS1(X) memset((X), -1, sizeof((X)))
#define LEN(X) strlen(X)
#define rg(a,x,y) (a+x), (a+y+1)
#define vrg(a,x,y) (a.begin()+x),(a.begin()+y+1)
#define all(x) (x).begin(),(x).end()
#define rall(x) (x).rbegin(),(x).rend()
#define _sum(a) accumulate(a, 0ll)
#define _max(a,b) *max_element(a,b)
#define pb push_back
#define pr make_pair
#define bugc(_) cerr << (#_) << " = " << (_) << endl;
#define sz(x) ((int)x.size())
#define L(i,u) for (register int i=head[u]; i; i=nxt[i])
#define fr1(i,a,b) for (register int i=(a); i<=(b); i++)
#define fr2(i,a,b) for (register int i=(a); i>=(b); i--)
#define ios  ios::sync_with_stdio(false);
#define lson l,mid,rt << 1
#define rson mid + 1,r,rt << 1 | 1
///vector(len,val);
using namespace std;

typedef long long ll;
typedef double db;
int xx[4] = {1,-1,0,0};
int yy[4] = {0,0,1,-1};
const double eps = 1e-9;
typedef pair<int,int>  P;
typedef pair<ll,ll>  Pl;
typedef pair<double,double>  PP;
const int maxn = 2e6 + 5000;
const ll mod = 1e9 + 7;
const int INF(0x3f3f3f3f);
const ll INFL(0x3f3f3f3f3f3f3f3fll);
inline int sign(db a) { return a < -eps ? -1 : a > eps;}
//inline int cmp(db a,db b){ return sign(a - b);}

ll mul(ll a,ll b,ll c) { ll res = 1; while(b) {  if(b & 1) res *= a,res %= c;  a *= a,a %= c,b >>= 1;  }  return res;}
ll mulll(ll a,ll b,ll c) { ll res = 1; while(b) {  if(b & 1) res *= a,res %= c;  a *= a,a %= c,b >>= 1;  }  return res;}
ll phi(ll x) {  ll res = x;  for(ll i = 2; i * i <= x; i++) { if(x % i == 0) res = res / i * (i - 1);   while(x % i == 0) x /= i;   }  if(x > 1) res = res / x  * (x - 1);    return res;}
template <typename A, typename B> inline bool chmin(A &a, B b){if(a > b) {a = b; return 1;} return 0;}
template <typename A, typename B> inline bool chmax(A &a, B b){if(a < b) {a = b; return 1;} return 0;}
template <typename A, typename B> inline ll add(A x, B y) {if(x + y < 0) return x + y + mod; return x + y >= mod ? x + y - mod : x + y;}
template <typename A, typename B> inline void add2(A &x, B y) {if(x + y < 0) x = x + y + mod; else x = (x + y >= mod ? x + y - mod : x + y);}
template <typename A, typename B> inline ll mul1(A x, B y) {return 1ll * x * y % mod;} /// x * y % mod;
template <typename A, typename B> inline void mul2(A &x, B y) {x = (1ll * x * y % mod + mod) % mod;} /// return x * y
template <typename A> inline void debug(A a){cout << a << '\n';}
template <typename A> inline ll sqr(A x){return 1ll * x * x;}
template <typename A> A inv(A x) {return mulll(x, mod - 2,mod);}
template <typename A> void bugl(A a[],int l,int r) { for(int i = l;i <= r;i++) cout << a[i] << " "; cout << endl;  }
template <typename A> void bug(A a[],int l,int r) { for(int i = l;i <= r;i++) cout << a[i] << " "; cout << endl;  }
template<class T>void wt(const T& x){cout << x << endl;}
template<class T>void wt(const T& x, char c){cout << x << c;}
template<class T>void wt(const T& x, const string& s){cout << x << s;}
template<class T>void wt(const T& x, int rnd){  cout << fixed << setprecision(rnd) << x << endl;}
template<class T> inline void read(T &x){  x=0; char c=getchar(); int f=1;  while (!isdigit(c)) {if (c=='-') f=-1; c=getchar();} while (isdigit(c)) {x=x*10+c-'0'; c=getchar();} x*=f;}
inline ll lowbit(ll x){ return (x & (-x)); }
inline void debug(){  cout << "###!!!" << endl;}
//inline void bugl(int a[],int l,int r){ for(int i = l;i <= r;i++) cout << a[i] << " "; cout << endl; }
//inline void bug(int a[],int l,int r){ for(int i = l;i <= r;i++) cout << a[i] << " ";  }
 ll n;
Pl p[maxn];
int main() {
    int m;
    while(cin >> n >> m) {
        vector<int>v; ios;
        for(int i = 1; i <= m; i++) {
            int x,y;
            cin >>x >>y;
            if(x < y) v.pb(1);
            else v.pb(2);
        }
        int ans = 1;set<int>s;
        for(auto d:v) s.insert(d);
        ans = s.size();
        wt(ans);
        for(auto d:v) cout << d << " ";
        cout << endl;
    }
    return 0;
}


//#include <bits/stdc++.h>
//#include <time.h>
//#define fi first
//#define se second
//#define endll "\n"
//#define MS0(X) memset((X), 0, sizeof((X)))
//#define MS1(X) memset((X), -1, sizeof((X)))
//#define LEN(X) strlen(X)
//#define rg(a,x,y) (a+x), (a+y+1)
//#define vrg(a,x,y) (a.begin()+x),(a.begin()+y+1)
//#define all(x) (x).begin(),(x).end()
//#define rall(x) (x).rbegin(),(x).rend()
//#define _sum(a) accumulate(a, 0ll)
//#define _max(a,b) *max_element(a,b)
//#define pb push_back
//#define pr make_pair
//#define bugc(_) cerr << (#_) << " = " << (_) << endl;
//#define sz(x) ((int)x.size())
//#define L(i,u) for (register int i=head[u]; i; i=nxt[i])
//#define fr1(i,a,b) for (register int i=(a); i<=(b); i++)
//#define fr2(i,a,b) for (register int i=(a); i>=(b); i--)
//#define ios  ios::sync_with_stdio(false);
//#define lson l,mid,rt << 1
//#define rson mid + 1,r,rt << 1 | 1
/////vector(len,val);
//using namespace std;
//
//typedef long long ll;
//typedef double db;
//int xx[4] = {1,-1,0,0};
//int yy[4] = {0,0,1,-1};
//const double eps = 1e-9;
//typedef pair<int,int>  P;
//typedef pair<ll,ll>  Pl;
//typedef pair<double,double>  PP;
//const int maxn = 2e6 + 5000;
//const ll mod = 1e9 + 7;
//const int INF(0x3f3f3f3f);
//const ll INFL(0x3f3f3f3f3f3f3f3fll);
//inline int sign(db a) { return a < -eps ? -1 : a > eps;}
////inline int cmp(db a,db b){ return sign(a - b);}
//
//ll mul(ll a,ll b,ll c) { ll res = 1; while(b) {  if(b & 1) res *= a,res %= c;  a *= a,a %= c,b >>= 1;  }  return res;}
//ll mulll(ll a,ll b,ll c) { ll res = 1; while(b) {  if(b & 1) res *= a,res %= c;  a *= a,a %= c,b >>= 1;  }  return res;}
//ll phi(ll x) {  ll res = x;  for(ll i = 2; i * i <= x; i++) { if(x % i == 0) res = res / i * (i - 1);   while(x % i == 0) x /= i;   }  if(x > 1) res = res / x  * (x - 1);    return res;}
//template <typename A, typename B> inline bool chmin(A &a, B b){if(a > b) {a = b; return 1;} return 0;}
//template <typename A, typename B> inline bool chmax(A &a, B b){if(a < b) {a = b; return 1;} return 0;}
//template <typename A, typename B> inline ll add(A x, B y) {if(x + y < 0) return x + y + mod; return x + y >= mod ? x + y - mod : x + y;}
//template <typename A, typename B> inline void add2(A &x, B y) {if(x + y < 0) x = x + y + mod; else x = (x + y >= mod ? x + y - mod : x + y);}
//template <typename A, typename B> inline ll mul1(A x, B y) {return 1ll * x * y % mod;} /// x * y % mod;
//template <typename A, typename B> inline void mul2(A &x, B y) {x = (1ll * x * y % mod + mod) % mod;} /// return x * y
//template <typename A> inline void debug(A a){cout << a << '\n';}
//template <typename A> inline ll sqr(A x){return 1ll * x * x;}
//template <typename A> A inv(A x) {return mulll(x, mod - 2,mod);}
//template <typename A> void bugl(A a[],int l,int r) { for(int i = l;i <= r;i++) cout << a[i] << " "; cout << endl;  }
//template <typename A> void bug(A a[],int l,int r) { for(int i = l;i <= r;i++) cout << a[i] << " "; cout << endl;  }
//template<class T>void wt(const T& x){cout << x << endl;}
//template<class T>void wt(const T& x, char c){cout << x << c;}
//template<class T>void wt(const T& x, const string& s){cout << x << s;}
//template<class T>void wt(const T& x, int rnd){  cout << fixed << setprecision(rnd) << x << endl;}
//template<class T> inline void read(T &x){  x=0; char c=getchar(); int f=1;  while (!isdigit(c)) {if (c=='-') f=-1; c=getchar();} while (isdigit(c)) {x=x*10+c-'0'; c=getchar();} x*=f;}
//inline ll lowbit(ll x){ return (x & (-x)); }
//inline void debug(){  cout << "###!!!" << endl;}
////inline void bugl(int a[],int l,int r){ for(int i = l;i <= r;i++) cout << a[i] << " "; cout << endl; }
////inline void bug(int a[],int l,int r){ for(int i = l;i <= r;i++) cout << a[i] << " ";  }
// ll n;
//Pl p[maxn];
//bool cmp(P a,P b) {
//    return a.fi - a.se >= b.fi - b.se;
//}
//ll op[33];
//ll l[maxn];
//int main() {
//    int t;
//    op[1] = 1;
//    for(int i = 2;i <= 20;i++) op[i] = op[i - 1] * 2;
//    cin >> t;
//    while(t--) {
//        string str;
//        cin >> str; ll ans = 0; int id = 0;
//        for(int i = 0;i < str.size();i++){
//                l[i] = 0;   if(str[i] == '1') l[i] = id,id = i;
//        }
//        for(int i = str.size() - 1;i >= 0;i--){
//            ll val = 0,cnt = 1;
//            if(str[i] == '1') val += 1,ans++;
//            for(int j = i - 1,k = 0;j >= 0 && k <= 20;k++,j--){
//                cnt++;
//                if(str[j] == '1') val += op[cnt];
//                if(val > cnt){
//                    int cha = val - cnt;
//                    if(l[j] - j - 1 >= cha)ans++;
//                }
//                if(val == cnt) ans++;
//            }
//            bugc(ans);
//        } wt(ans);
//    }
//    return 0;
//}
//
//

#include <bits/stdc++.h>
#include <time.h>
#define fi first
#define se second
#define endll "\n"
#define MS0(X) memset((X), 0, sizeof((X)))
#define MS1(X) memset((X), -1, sizeof((X)))
#define LEN(X) strlen(X)
#define rg(a,x,y) (a+x), (a+y+1)
#define vrg(a,x,y) (a.begin()+x),(a.begin()+y+1)
#define all(x) (x).begin(),(x).end()
#define rall(x) (x).rbegin(),(x).rend()
#define _sum(a) accumulate(a, 0ll)
#define _max(a,b) *max_element(a,b)
#define pb push_back
#define pr make_pair
#define bugc(_) cerr << (#_) << " = " << (_) << endl;
#define sz(x) ((int)x.size())
#define L(i,u) for (register int i=head[u]; i; i=nxt[i])
#define fr1(i,a,b) for (register int i=(a); i<=(b); i++)
#define fr2(i,a,b) for (register int i=(a); i>=(b); i--)
#define ios  ios::sync_with_stdio(false);
#define lson l,mid,rt << 1
#define rson mid + 1,r,rt << 1 | 1
///vector(len,val);
using namespace std;

typedef long long ll;
typedef double db;
int xx[4] = {1,-1,0,0};
int yy[4] = {0,0,1,-1};
const double eps = 1e-9;
typedef pair<int,int>  P;
typedef pair<ll,ll>  Pl;
typedef pair<double,double>  PP;
const int maxn = 2e6 + 5000;
const ll mod = 1e9 + 7;
const int INF(0x3f3f3f3f);
const ll INFL(0x3f3f3f3f3f3f3f3fll);
inline int sign(db a) { return a < -eps ? -1 : a > eps;}
//inline int cmp(db a,db b){ return sign(a - b);}

ll mul(ll a,ll b,ll c) { ll res = 1; while(b) {  if(b & 1) res *= a,res %= c;  a *= a,a %= c,b >>= 1;  }  return res;}
ll mulll(ll a,ll b,ll c) { ll res = 1; while(b) {  if(b & 1) res *= a,res %= c;  a *= a,a %= c,b >>= 1;  }  return res;}
ll phi(ll x) {  ll res = x;  for(ll i = 2; i * i <= x; i++) { if(x % i == 0) res = res / i * (i - 1);   while(x % i == 0) x /= i;   }  if(x > 1) res = res / x  * (x - 1);    return res;}
template <typename A, typename B> inline bool chmin(A &a, B b){if(a > b) {a = b; return 1;} return 0;}
template <typename A, typename B> inline bool chmax(A &a, B b){if(a < b) {a = b; return 1;} return 0;}
template <typename A, typename B> inline ll add(A x, B y) {if(x + y < 0) return x + y + mod; return x + y >= mod ? x + y - mod : x + y;}
template <typename A, typename B> inline void add2(A &x, B y) {if(x + y < 0) x = x + y + mod; else x = (x + y >= mod ? x + y - mod : x + y);}
template <typename A, typename B> inline ll mul1(A x, B y) {return 1ll * x * y % mod;} /// x * y % mod;
template <typename A, typename B> inline void mul2(A &x, B y) {x = (1ll * x * y % mod + mod) % mod;} /// return x * y
template <typename A> inline void debug(A a){cout << a << '\n';}
template <typename A> inline ll sqr(A x){return 1ll * x * x;}
template <typename A> A inv(A x) {return mulll(x, mod - 2,mod);}
template <typename A> void bugl(A a[],int l,int r) { for(int i = l;i <= r;i++) cout << a[i] << " "; cout << endl;  }
template <typename A> void bug(A a[],int l,int r) { for(int i = l;i <= r;i++) cout << a[i] << " "; cout << endl;  }
template<class T>void wt(const T& x){cout << x << endl;}
template<class T>void wt(const T& x, char c){cout << x << c;}
template<class T>void wt(const T& x, const string& s){cout << x << s;}
template<class T>void wt(const T& x, int rnd){  cout << fixed << setprecision(rnd) << x << endl;}
template<class T> inline void read(T &x){  x=0; char c=getchar(); int f=1;  while (!isdigit(c)) {if (c=='-') f=-1; c=getchar();} while (isdigit(c)) {x=x*10+c-'0'; c=getchar();} x*=f;}
inline ll lowbit(ll x){ return (x & (-x)); }
inline void debug(){  cout << "###!!!" << endl;}
//inline void bugl(int a[],int l,int r){ for(int i = l;i <= r;i++) cout << a[i] << " "; cout << endl; }
//inline void bug(int a[],int l,int r){ for(int i = l;i <= r;i++) cout << a[i] << " ";  }
 ll n;
 int vis[5050];
 vector<int>v[maxn];
 void dfs(int x){
    vis[x] = 1;
    for(auto &d:v[x]) if(!vis[d]) dfs(d);
    return ;
 }
 bool check(int x,int y){
    MS0(vis);
     dfs(x);
     return vis[y];
 }
int main() {
    int m;ios;
    while(cin >> n >> m) {
        vector<int>vv;
        int flag = 0;
        for(int i = 1; i <= m; i++) {
            int x,y;
            cin >> x >>y;
            if(check(y,x)) vv.pb(2),flag = 1;
            else vv.pb(1);
            v[x].pb(y);
        }
        wt(flag + 1);
        for(auto d:vv) cout << d << " ";
        cout << endl;
    }
    return 0;
}


/*
#include <bits/stdc++.h>
#include <time.h>
#define fi first
#define se second
#define endll "\n"
#define MS0(X) memset((X), 0, sizeof((X)))
#define MS1(X) memset((X), -1, sizeof((X)))
#define LEN(X) strlen(X)
#define rg(a,x,y) (a+x), (a+y+1)
#define vrg(a,x,y) (a.begin()+x),(a.begin()+y+1)
#define all(x) (x).begin(),(x).end()
#define rall(x) (x).rbegin(),(x).rend()
#define _sum(a) accumulate(a, 0ll)
#define _max(a,b) *max_element(a,b)
#define pb push_back
#define pr make_pair
#define bugc(_) cerr << (#_) << " = " << (_) << endl;
#define sz(x) ((int)x.size())
#define L(i,u) for (register int i=head[u]; i; i=nxt[i])
#define fr1(i,a,b) for (register int i=(a); i<=(b); i++)
#define fr2(i,a,b) for (register int i=(a); i>=(b); i--)
#define ios  ios::sync_with_stdio(false);
#define lson l,mid,rt << 1
#define rson mid + 1,r,rt << 1 | 1
///vector(len,val);
using namespace std;

typedef long long ll;
typedef double db;
int xx[4] = {1,-1,0,0};
int yy[4] = {0,0,1,-1};
const double eps = 1e-9;
typedef pair<int,int>  P;
typedef pair<ll,ll>  Pl;
typedef pair<double,double>  PP;
const int maxn = 2e6 + 5000;
const ll mod = 1e9 + 7;
const int INF(0x3f3f3f3f);
const ll INFL(0x3f3f3f3f3f3f3f3fll);
inline int sign(db a) { return a < -eps ? -1 : a > eps;}
//inline int cmp(db a,db b){ return sign(a - b);}

ll mul(ll a,ll b,ll c) { ll res = 1; while(b) {  if(b & 1) res *= a,res %= c;  a *= a,a %= c,b >>= 1;  }  return res;}
ll mulll(ll a,ll b,ll c) { ll res = 1; while(b) {  if(b & 1) res *= a,res %= c;  a *= a,a %= c,b >>= 1;  }  return res;}
ll phi(ll x) {  ll res = x;  for(ll i = 2; i * i <= x; i++) { if(x % i == 0) res = res / i * (i - 1);   while(x % i == 0) x /= i;   }  if(x > 1) res = res / x  * (x - 1);    return res;}
template <typename A, typename B> inline bool chmin(A &a, B b){if(a > b) {a = b; return 1;} return 0;}
template <typename A, typename B> inline bool chmax(A &a, B b){if(a < b) {a = b; return 1;} return 0;}
template <typename A, typename B> inline ll add(A x, B y) {if(x + y < 0) return x + y + mod; return x + y >= mod ? x + y - mod : x + y;}
template <typename A, typename B> inline void add2(A &x, B y) {if(x + y < 0) x = x + y + mod; else x = (x + y >= mod ? x + y - mod : x + y);}
template <typename A, typename B> inline ll mul1(A x, B y) {return 1ll * x * y % mod;} /// x * y % mod;
template <typename A, typename B> inline void mul2(A &x, B y) {x = (1ll * x * y % mod + mod) % mod;} /// return x * y
template <typename A> inline void debug(A a){cout << a << '\n';}
template <typename A> inline ll sqr(A x){return 1ll * x * x;}
template <typename A> A inv(A x) {return mulll(x, mod - 2,mod);}
template <typename A> void bugl(A a[],int l,int r) { for(int i = l;i <= r;i++) cout << a[i] << " "; cout << endl;  }
template <typename A> void bug(A a[],int l,int r) { for(int i = l;i <= r;i++) cout << a[i] << " "; cout << endl;  }
template<class T>void wt(const T& x){cout << x << endl;}
template<class T>void wt(const T& x, char c){cout << x << c;}
template<class T>void wt(const T& x, const string& s){cout << x << s;}
template<class T>void wt(const T& x, int rnd){  cout << fixed << setprecision(rnd) << x << endl;}
template<class T> inline void read(T &x){  x=0; char c=getchar(); int f=1;  while (!isdigit(c)) {if (c=='-') f=-1; c=getchar();} while (isdigit(c)) {x=x*10+c-'0'; c=getchar();} x*=f;}
inline ll lowbit(ll x){ return (x & (-x)); }
inline void debug(){  cout << "###!!!" << endl;}
//inline void bugl(int a[],int l,int r){ for(int i = l;i <= r;i++) cout << a[i] << " "; cout << endl; }
//inline void bug(int a[],int l,int r){ for(int i = l;i <= r;i++) cout << a[i] << " ";  }
 ll n,k;
ll a[maxn];
namespace com{
    ll W,W0;
    const ll ljc = 1e9+7;
    struct comp{
        ll x,y;
        comp(ll xx=0,ll yy=0){x=xx,y=yy;}
    };
    comp operator * (comp a,comp b){
        return comp((a.x*b.x%ljc+a.y*b.y%ljc*W%ljc)%ljc,(a.y*b.x%ljc+a.x*b.y%ljc)%ljc);
    }
    inline ll fast_pow(ll a,ll b,ll p){
        ll t=1;a%=p;
        while (b){
            if (b&1) t=t*a%p;
            b>>=1;a=a*a%p;
        }
        return t;
    }
    inline comp cfast_pow(comp a,ll b,ll p){
        comp t=comp(1,0);
        while (b){
            if (b&1) t=t*a;
            b>>=1;a=a*a;
        }
        return t;
    }
    inline pair<ll,ll> Cipolla(ll x){
        if (fast_pow(x,(ljc-1)>>1,ljc)==ljc-1) return make_pair(-1,-1);
        srand(time(NULL));
        while (1){
            W0=rand()%ljc;W=(W0*W0%ljc-x+ljc)%ljc;
            if (fast_pow(W,(ljc-1)>>1,ljc)==ljc-1) break;
        }
        comp a=cfast_pow(comp(W0,1),(ljc+1)>>1,ljc);
        return make_pair(min(a.x,ljc-a.x),max(a.x,ljc-a.x));
    }
}
ll solve(ll a) {		//解x^2≡a mod ljc  x可以是个多项式
    if (a==0) return 0;
    pair<ll,ll> ans=com::Cipolla(a);
    return ans.first;
}
int main()
{
	x = solve(x);
    return 0;
}

*/

/*

#include <bits/stdc++.h>
#include <time.h>
#define fi first
#define se second
#define endll "\n"
#define MS0(X) memset((X), 0, sizeof((X)))
#define MS1(X) memset((X), -1, sizeof((X)))
#define LEN(X) strlen(X)
#define rg(a,x,y) (a+x), (a+y+1)
#define vrg(a,x,y) (a.begin()+x),(a.begin()+y+1)
#define all(x) (x).begin(),(x).end()
#define rall(x) (x).rbegin(),(x).rend()
#define _sum(a) accumulate(a, 0ll)
#define _max(a,b) *max_element(a,b)
#define pb push_back
#define pr make_pair
#define bugc(_) cerr << (#_) << " = " << (_) << endl;
#define sz(x) ((int)x.size())
#define L(i,u) for (register int i=head[u]; i; i=nxt[i])
#define fr1(i,a,b) for (register int i=(a); i<=(b); i++)
#define fr2(i,a,b) for (register int i=(a); i>=(b); i--)
#define ios  ios::sync_with_stdio(false);
#define lson l,mid,rt << 1
#define rson mid + 1,r,rt << 1 | 1
///vector(len,val);
using namespace std;

typedef long long ll;
typedef double db;
int xx[4] = {1,-1,0,0};
int yy[4] = {0,0,1,-1};
const double eps = 1e-9;
typedef pair<int,int>  P;
typedef pair<ll,ll>  Pl;
typedef pair<double,double>  PP;
const int maxn = 2e6 + 5000;
const ll mod = 1e9 + 7;
const int INF(0x3f3f3f3f);
const ll INFL(0x3f3f3f3f3f3f3f3fll);
inline int sign(db a) { return a < -eps ? -1 : a > eps;}
//inline int cmp(db a,db b){ return sign(a - b);}

ll mul(ll a,ll b,ll c) { ll res = 1; while(b) {  if(b & 1) res *= a,res %= c;  a *= a,a %= c,b >>= 1;  }  return res;}
ll mulll(ll a,ll b,ll c) { ll res = 1; while(b) {  if(b & 1) res *= a,res %= c;  a *= a,a %= c,b >>= 1;  }  return res;}
ll phi(ll x) {  ll res = x;  for(ll i = 2; i * i <= x; i++) { if(x % i == 0) res = res / i * (i - 1);   while(x % i == 0) x /= i;   }  if(x > 1) res = res / x  * (x - 1);    return res;}
template <typename A, typename B> inline bool chmin(A &a, B b){if(a > b) {a = b; return 1;} return 0;}
template <typename A, typename B> inline bool chmax(A &a, B b){if(a < b) {a = b; return 1;} return 0;}
template <typename A, typename B> inline ll add(A x, B y) {if(x + y < 0) return x + y + mod; return x + y >= mod ? x + y - mod : x + y;}
template <typename A, typename B> inline void add2(A &x, B y) {if(x + y < 0) x = x + y + mod; else x = (x + y >= mod ? x + y - mod : x + y);}
template <typename A, typename B> inline ll mul1(A x, B y) {return 1ll * x * y % mod;} /// x * y % mod;
template <typename A, typename B> inline void mul2(A &x, B y) {x = (1ll * x * y % mod + mod) % mod;} /// return x * y
template <typename A> inline void debug(A a){cout << a << '\n';}
template <typename A> inline ll sqr(A x){return 1ll * x * x;}
template <typename A> A inv(A x) {return mulll(x, mod - 2,mod);}
template <typename A> void bugl(A a[],int l,int r) { for(int i = l;i <= r;i++) cout << a[i] << " "; cout << endl;  }
template <typename A> void bug(A a[],int l,int r) { for(int i = l;i <= r;i++) cout << a[i] << " "; cout << endl;  }
template<class T>void wt(const T& x){cout << x << endl;}
template<class T>void wt(const T& x, char c){cout << x << c;}
template<class T>void wt(const T& x, const string& s){cout << x << s;}
template<class T>void wt(const T& x, int rnd){  cout << fixed << setprecision(rnd) << x << endl;}
template<class T> inline void read(T &x){  x=0; char c=getchar(); int f=1;  while (!isdigit(c)) {if (c=='-') f=-1; c=getchar();} while (isdigit(c)) {x=x*10+c-'0'; c=getchar();} x*=f;}
inline ll lowbit(ll x){ return (x & (-x)); }
inline void debug(){  cout << "###!!!" << endl;}
//inline void bugl(int a[],int l,int r){ for(int i = l;i <= r;i++) cout << a[i] << " "; cout << endl; }
//inline void bug(int a[],int l,int r){ for(int i = l;i <= r;i++) cout << a[i] << " ";  }
 ll n,k;
ll a[maxn];

int main()
{
	char c;
	while(c = getchar()){
		if(c == -1) break;
		if(c != '-') printf("%c", c);;
	}
    return 0;
}
*/

 #include <bits/stdc++.h>
#include <time.h>
#define fi first
#define se second
#define endll "\n"
#define MS0(X) memset((X), 0, sizeof((X)))
#define MS1(X) memset((X), -1, sizeof((X)))
#define LEN(X) strlen(X)
#define rg(a,x,y) (a+x), (a+y+1)
#define vrg(a,x,y) (a.begin()+x),(a.begin()+y+1)
#define all(x) (x).begin(),(x).end()
#define rall(x) (x).rbegin(),(x).rend()
#define _sum(a) accumulate(a, 0ll)
#define _max(a,b) *max_element(a,b)
#define pb push_back
#define pr make_pair
#define bugc(_) cerr << (#_) << " = " << (_) << endl;
#define sz(x) ((int)x.size())
#define L(i,u) for (register int i=head[u]; i; i=nxt[i])
#define fr1(i,a,b) for (register int i=(a); i<=(b); i++)
#define fr2(i,a,b) for (register int i=(a); i>=(b); i--)
#define ios  ios::sync_with_stdio(false);
#define lson l,mid,rt << 1
#define rson mid + 1,r,rt << 1 | 1
///vector(len,val);
using namespace std;

typedef long long ll;
typedef double db;
int xx[4] = {1,-1,0,0};
int yy[4] = {0,0,1,-1};
const double eps = 1e-9;
typedef pair<int,int>  P;
typedef pair<ll,ll>  Pl;
typedef pair<double,double>  PP;
const int maxn = 2e6 + 5000;
const ll mod = 1e9 + 7;
const int INF(0x3f3f3f3f);
const ll INFL(0x3f3f3f3f3f3f3f3fll);
inline int sign(db a) { return a < -eps ? -1 : a > eps;}
//inline int cmp(db a,db b){ return sign(a - b);}

ll mul(ll a,ll b,ll c) { ll res = 1; while(b) {  if(b & 1) res *= a,res %= c;  a *= a,a %= c,b >>= 1;  }  return res;}
ll mulll(ll a,ll b,ll c) { ll res = 1; while(b) {  if(b & 1) res *= a,res %= c;  a *= a,a %= c,b >>= 1;  }  return res;}
ll phi(ll x) {  ll res = x;  for(ll i = 2; i * i <= x; i++) { if(x % i == 0) res = res / i * (i - 1);   while(x % i == 0) x /= i;   }  if(x > 1) res = res / x  * (x - 1);    return res;}
template <typename A, typename B> inline bool chmin(A &a, B b){if(a > b) {a = b; return 1;} return 0;}
template <typename A, typename B> inline bool chmax(A &a, B b){if(a < b) {a = b; return 1;} return 0;}
template <typename A, typename B> inline ll add(A x, B y) {if(x + y < 0) return x + y + mod; return x + y >= mod ? x + y - mod : x + y;}
template <typename A, typename B> inline void add2(A &x, B y) {if(x + y < 0) x = x + y + mod; else x = (x + y >= mod ? x + y - mod : x + y);}
template <typename A, typename B> inline ll mul1(A x, B y) {return 1ll * x * y % mod;} /// x * y % mod;
template <typename A, typename B> inline void mul2(A &x, B y) {x = (1ll * x * y % mod + mod) % mod;} /// return x * y
template <typename A> inline void debug(A a){cout << a << '\n';}
template <typename A> inline ll sqr(A x){return 1ll * x * x;}
template <typename A> A inv(A x) {return mulll(x, mod - 2,mod);}
template <typename A> void bugl(A a[],int l,int r) { for(int i = l;i <= r;i++) cout << a[i] << " "; cout << endl;  }
template <typename A> void bug(A a[],int l,int r) { for(int i = l;i <= r;i++) cout << a[i] << " "; cout << endl;  }
template<class T>void wt(const T& x){cout << x << endl;}
template<class T>void wt(const T& x, char c){cout << x << c;}
template<class T>void wt(const T& x, const string& s){cout << x << s;}
template<class T>void wt(const T& x, int rnd){  cout << fixed << setprecision(rnd) << x << endl;}
template<class T> inline void read(T &x){  x=0; char c=getchar(); int f=1;  while (!isdigit(c)) {if (c=='-') f=-1; c=getchar();} while (isdigit(c)) {x=x*10+c-'0'; c=getchar();} x*=f;}
inline ll lowbit(ll x){ return (x & (-x)); }
inline void debug(){  cout << "###!!!" << endl;}
//inline void bugl(int a[],int l,int r){ for(int i = l;i <= r;i++) cout << a[i] << " "; cout << endl; }
//inline void bug(int a[],int l,int r){ for(int i = l;i <= r;i++) cout << a[i] << " ";  }
 ll n;
 int vis[5050];
 vector<int>v[maxn];
 void dfs(int x){
    vis[x] = 1;
    for(auto &d:v[x]) if(!vis[d]) dfs(d);
    return ;
 }
 bool check(int x,int y){
    MS0(vis);
     dfs(x);
     return vis[y];
 }
int main() {
    int m;ios;
    while(cin >> n >> m) {
        vector<int>vv;
        int flag = 0;
        for(int i = 1; i <= m; i++) {
            int x,y;
            cin >> x >>y;
            if(check(y,x)) vv.pb(2),flag = 1;
            else vv.pb(1),
            v[x].pb(y);
        }
        wt(flag + 1);
        for(auto d:vv) cout << d << " ";
        cout << endl;
    }
    return 0;
}

/*3 6
1 2
2 3
3 1
2 1
1 3
3 2
*/


#include <set>
#include <map>
#include <queue>
#include <cmath>
#include <vector>
#include <stack>
#include <limits.h>
#include <cstdio>
#include <bitset>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
int Gcd(int a,int b){if (b == 0) return a; return Gcd(b , a%b);}
int Lcm(int a, int b){ return a/Gcd(a,b)*b;}
inline int read(){
    int f = 1, x = 0;char ch = getchar();
    while (ch > '9' || ch < '0'){if (ch == '-')f = -f;ch = getchar();}
    while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}
const int maxn = 1e5 + 10;
struct edge{
    int to,nex,id;
    int c;
}ed[maxn << 1];
int head[maxn],tot;
int in[maxn];
int vis[maxn];
int color[maxn];
void add(int u,int v,int id){
    ed[tot] = (edge){v,head[u]};
    ed[tot].id = id;
    head[u] = tot++;
}
int tag = 0;
void dfs(int u){
    in[u] = -INT_MAX;
    for(int i=head[u]; ~i; i = ed[i].nex){
        int v = ed[i].to;
        if (in[v] > 0){
            dfs(v);
        }else if (in[v] == -INT_MAX){
            color[ed[i].id] = 1;
        }
    }
}
queue<int> q;
int main(){
    int n = read(),m = read();
    memset(head,-1,sizeof(head));
    for(int i=1; i<=m; i++){
        int u = read(),v = read();
        add(u,v,i);
        in[v]++;
    }
    for(int i=1; i<=n; i++){
        if (in[i] == 0) {
            q.push(i);
        }
    }
    while(!q.empty()){
        int u = q.front(); q.pop();
        for(int i=head[u]; ~i; i=ed[i].nex){
            int v = ed[i].to;
            in[v]--;
            if (in[v] == 0){
                q.push(v);
            }
        }
    }
    int tag = 1;
    for(int i=1; i<=n; i++){
        if (in[i] > 0){
            tag = 0;
            dfs(i);
        }
    }
    if (!tag) cout << 2 << endl;
    else cout << 1 << endl;
    for(int i=1; i<=m; i++){
        cout << color[i] + 1 << ' ';
    }
    cout << endl;
    return 0;
}


#include <set>
#include <map>
#include <queue>
#include <cmath>
#include <vector>
#include <stack>
#include <limits.h>
#include <cstdio>
#include <bitset>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
int Gcd(int a,int b){if (b == 0) return a; return Gcd(b , a%b);}
int Lcm(int a, int b){ return a/Gcd(a,b)*b;}
inline int read(){
    int f = 1, x = 0;char ch = getchar();
    while (ch > '9' || ch < '0'){if (ch == '-')f = -f;ch = getchar();}
    while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}
const int maxn = 1e5 + 10;
struct edge{
    int to,nex,id;
    int c;
}ed[maxn << 1];
int head[maxn],tot;
int in[maxn];
int vis[maxn];
int color[maxn];
void add(int u,int v,int id){
    ed[tot] = (edge){v,head[u]};
    ed[tot].id = id;
    head[u] = tot++;
}
int tag = 0;
void dfs(int u,int c){
    in[u] = 0;
    for(int i=head[u]; ~i; i = ed[i].nex){
        int v = ed[i].to;
        if (in[v] == 0){
            color[ed[i].id] = c;
            dfs(v,c^1);
        }
    }
}
queue<int> q;
int main(){
    int n = read(),m = read();
    memset(head,-1,sizeof(head));
    for(int i=1; i<=m; i++){
        int u = read(),v = read();
        add(u,v,i);
        in[v]++;
    }
    for(int i=1; i<=n; i++){
        if (in[i] == 0) {
            vis[i] = 1;
            q.push(i);
        }
    }
    while(!q.empty()){
        int u = q.front(); q.pop();
        for(int i=head[u]; ~i; i=ed[i].nex){
            int v = ed[i].to;
            in[v]--;
            if (in[v] == 0){
                q.push(v);
                vis[v] = 1;
            }
        }
    }
    int tag = 1;
    for(int i=1; i<=n; i++){
        if (in[i] > 0){
            tag = 0;
            dfs(i,0);
        }
    }
    if (!tag) cout << 2 << endl;
    else cout << 1 << endl;
    for(int i=1; i<=m; i++){
        cout << color[i] + 1 << ' ';
    }
    cout << endl;
    return 0;
}


#include <set>
#include <map>
#include <queue>
#include <cmath>
#include <vector>
#include <stack>
#include <limits.h>
#include <cstdio>
#include <bitset>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
int Gcd(int a,int b){if (b == 0) return a; return Gcd(b , a%b);}
int Lcm(int a, int b){ return a/Gcd(a,b)*b;}
inline int read(){
    int f = 1, x = 0;char ch = getchar();
    while (ch > '9' || ch < '0'){if (ch == '-')f = -f;ch = getchar();}
    while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}
const int maxn = 1e5 + 10;
struct edge{
    int to,nex,id;
    int c;
}ed[maxn << 1];
int head[maxn],tot;
int in[maxn];
int vis[maxn];
int color[maxn];
void add(int u,int v,int id){
    ed[tot] = (edge){v,head[u]};
    ed[tot].id = id;
    head[u] = tot++;
}
int tag = 0;
void dfs(int u,int c){
    vis[u] = 1;
    for(int i=head[u]; ~i; i = ed[i].nex){
        int v = ed[i].to;
        if (vis[v] == 1 && !color[ed[i].id]){
            color[ed[i].id] = 1;
        }else{
            dfs(v,c);
        }
    }
}
queue<int> q;
int main(){
    int n = read(),m = read();
    memset(head,-1,sizeof(head));
    for(int i=1; i<=m; i++){
        int u = read(),v = read();
        add(u,v,i);
        in[v]++;
    }
    for(int i=1; i<=n; i++){
        if (in[i] == 0) {
            vis[i] = 1;
            q.push(i);
        }
    }
    while(!q.empty()){
        int u = q.front(); q.pop();
        for(int i=head[u]; ~i; i=ed[i].nex){
            int v = ed[i].to;
            in[v]--;
            if (in[v] == 0){
                q.push(v);
                vis[v] = 1;
            }
        }
    }
    int tag = 1;
    for(int i=1; i<=n; i++){
        if (vis[i] == 0){
            tag = 0;
            dfs(i,0);
        }
    }
    if (!tag) cout << 2 << endl;
    else cout << 1 << endl;
    for(int i=1; i<=m; i++){
        cout << color[i] + 1 << ' ';
    }
    cout << endl;
    return 0;
}


#include <set>
#include <map>
#include <queue>
#include <cmath>
#include <vector>
#include <stack>
#include <limits.h>
#include <cstdio>
#include <bitset>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
int Gcd(int a,int b){if (b == 0) return a; return Gcd(b , a%b);}
int Lcm(int a, int b){ return a/Gcd(a,b)*b;}
inline int read(){
    int f = 1, x = 0;char ch = getchar();
    while (ch > '9' || ch < '0'){if (ch == '-')f = -f;ch = getchar();}
    while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}
const int maxn = 1e5 + 10;
struct edge{ int to,nex; }ed[maxn << 1];
int head[maxn],tot;
int c[maxn],vis[maxn],ok[maxn];
int tag = 0;
void dfs(int u){
    vis[u] = ok[u] = 1;
    for(int i=head[u]; i ; i = ed[i].nex){
        int v = ed[i].to;
        if (vis[v]) c[i] = 2,tag = 1;
        else c[i] = 1;
        if (!ok[v]) dfs(v);
    }
    vis[u] = false;
}
void add(int u,int v){
    ed[++tot] = (edge){v,head[u]};
    head[u] = tot;
}
int main(){
    int n = read(),m = read();
    for(int i=1; i<=m; i++){
        add(read(),read());
    }
    for(int i=1; i<=n; i++){
        if (!ok[i]) dfs(i);
    }
    if (tag) cout << 2 << endl;
    else cout << 1 << endl;
    for(int i=1; i<=m; i++){
        cout << c[i] << ' ';
    }
    cout << endl;
    return 0;
}


#include <set>
#include <map>
#include <queue>
#include <cmath>
#include <vector>
#include <stack>
#include <limits.h>
#include <cstdio>
#include <bitset>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
int Gcd(int a,int b){if (b == 0) return a; return Gcd(b , a%b);}
int Lcm(int a, int b){ return a/Gcd(a,b)*b;}
inline int read(){
    int f = 1, x = 0;char ch = getchar();
    while (ch > '9' || ch < '0'){if (ch == '-')f = -f;ch = getchar();}
    while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}
const int maxn = 1e5 + 10;
struct edge{
    int to,nex,id;
    int c;
}ed[maxn << 1];
int head[maxn],tot;
int in[maxn];
int vis[maxn];
int color[maxn];
void add(int u,int v,int id){
    ed[tot] = (edge){v,head[u]};
    ed[tot].id = id;
    head[u] = tot++;
}
int tag = 0;
void dfs(int u,int c){
    vis[u] = 1;
    for(int i=head[u]; ~i; i = ed[i].nex){
        int v = ed[i].to;
        if (vis[v] == 0){
            color[ed[i].id] = c;
            dfs(v,c^1);
        }
    }
}
queue<int> q;
int main(){
    int n = read(),m = read();
    memset(head,-1,sizeof(head));
    for(int i=1; i<=m; i++){
        int u = read(),v = read();
        add(u,v,i);
        in[v]++;
    }
    for(int i=1; i<=n; i++){
        if (in[i] == 0) {
            vis[i] = 1;
            q.push(i);
        }
    }
    while(!q.empty()){
        int u = q.front(); q.pop();
        for(int i=head[u]; ~i; i=ed[i].nex){
            int v = ed[i].to;
            in[v]--;
            if (in[v] == 0){
                q.push(v);
                vis[v] = 1;
            }
        }
    }
    int tag = 1;
    for(int i=1; i<=n; i++){
        if (vis[i] == 0){
            tag = 0;
            dfs(i,0);
        }
    }
    if (!tag) cout << 2 << endl;
    else cout << 1 << endl;
    for(int i=1; i<=m; i++){
        cout << color[i] + 1 << ' ';
    }
    cout << endl;
    return 0;
}


#include <set>
#include <map>
#include <queue>
#include <cmath>
#include <vector>
#include <stack>
#include <limits.h>
#include <cstdio>
#include <bitset>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
int Gcd(int a,int b){if (b == 0) return a; return Gcd(b , a%b);}
int Lcm(int a, int b){ return a/Gcd(a,b)*b;}
inline int read(){
    int f = 1, x = 0;char ch = getchar();
    while (ch > '9' || ch < '0'){if (ch == '-')f = -f;ch = getchar();}
    while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}
const int maxn = 1e6 + 10;
struct edge{
    int to,nex,id;
    int c;
}ed[maxn << 1];
int head[maxn],tot;
int in[maxn];
int vis[maxn];
int color[maxn];
void add(int u,int v,int id){
    ed[tot] = (edge){v,head[u]};
    ed[tot].id = id;
    head[u] = tot++;
}
int tag = 0;
void dfs(int u,int c){
    in[u] = 0;
    for(int i=head[u]; ~i; i = ed[i].nex){
        int v = ed[i].to;
        if (in[v] == 0){
            color[ed[i].id] = c;
            dfs(v,c^1);
        }
    }
}
int main(){
    int n = read(),m = read();
    memset(head,-1,sizeof(head));
    for(int i=1; i<=m; i++){
        int u = read(),v = read();
        add(u,v,i);
        in[v]++;
    }
    queue<int> q;
    for(int i=1; i<=n; i++){
        if (in[i] == 0) {
            vis[i] = 1;
            q.push(i);
        }
    }
    while(!q.empty()){
        int u = q.front(); q.pop();
        for(int i=head[u]; ~i; i=ed[i].nex){
            int v = ed[i].to;
            in[v]--;
            if (in[v] == 0){
                q.push(v);
                vis[v] = 1;
            }
        }
    }
    int tag = 1;
    for(int i=1; i<=n; i++){
        if (in[i] > 0){
            tag = 0;
            dfs(i,0);
        }
    }
    if (!tag) cout << 2 << endl;
    else cout << 1 << endl;
    for(int i=1; i<=m; i++){
        cout << color[i] + 1 << ' ';
    }
    cout << endl;
    return 0;
}


#include <set>
#include <map>
#include <queue>
#include <cmath>
#include <vector>
#include <stack>
#include <limits.h>
#include <cstdio>
#include <bitset>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
int Gcd(int a,int b){if (b == 0) return a; return Gcd(b , a%b);}
int Lcm(int a, int b){ return a/Gcd(a,b)*b;}
inline int read(){
    int f = 1, x = 0;char ch = getchar();
    while (ch > '9' || ch < '0'){if (ch == '-')f = -f;ch = getchar();}
    while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}
const int maxn = 1e5 + 10;
struct edge{
    int to,nex,id;
    int c;
}ed[maxn << 1];
int head[maxn],tot;
int in[maxn];
int vis[maxn];
int color[maxn];
void add(int u,int v,int id){
    ed[tot] = (edge){v,head[u]};
    ed[tot].id = id;
    head[u] = tot++;
}
int tag = 0;
void dfs(int u){
    in[u] = 0;
    for(int i=head[u]; ~i; i = ed[i].nex){
        int v = ed[i].to;
        if (in[v] > 0){
            dfs(v);
        }else{
            color[ed[i].id] = 1;
        }
    }
}
queue<int> q;
int main(){
    int n = read(),m = read();
    memset(head,-1,sizeof(head));
    for(int i=1; i<=m; i++){
        int u = read(),v = read();
        add(u,v,i);
        in[v]++;
    }
    for(int i=1; i<=n; i++){
        if (in[i] == 0) {
            vis[i] = 1;
            q.push(i);
        }
    }
    while(!q.empty()){
        int u = q.front(); q.pop();
        for(int i=head[u]; ~i; i=ed[i].nex){
            int v = ed[i].to;
            in[v]--;
            if (in[v] == 0){
                q.push(v);
                vis[v] = 1;
            }
        }
    }
    int tag = 1;
    for(int i=1; i<=n; i++){
        if (vis[i] == 0){
            tag = 0;
            dfs(i);
        }
    }
    if (!tag) cout << 2 << endl;
    else cout << 1 << endl;
    for(int i=1; i<=m; i++){
        cout << color[i] + 1 << ' ';
    }
    cout << endl;
    return 0;
}


#include <set>
#include <map>
#include <queue>
#include <cmath>
#include <vector>
#include <stack>
#include <limits.h>
#include <cstdio>
#include <bitset>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
int Gcd(int a,int b){if (b == 0) return a; return Gcd(b , a%b);}
int Lcm(int a, int b){ return a/Gcd(a,b)*b;}
inline int read(){
    int f = 1, x = 0;char ch = getchar();
    while (ch > '9' || ch < '0'){if (ch == '-')f = -f;ch = getchar();}
    while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}
const int maxn = 1e6 + 10;
struct edge{
    int to,nex,c;
}ed[maxn << 1];
int head[maxn],tot;
int in[maxn];
int vis[maxn];
void add(int u,int v){
    ed[tot] = (edge){v,head[u]};
    head[u] = tot++;
}
int tag = 0;
int main(){
    int n = read(),m = read();
    memset(head,-1,sizeof(head));
    for(int i=1; i<=m; i++){
        int u = read(),v = read();
        add(u,v);
        in[v]++;
    }
    queue<int> q;
    for(int i=1; i<=n; i++){
        if (in[i] == 0) {
            vis[i] = 1;
            q.push(i);
        }
    }
    while(!q.empty()){
        int u = q.front(); q.pop();
        for(int i=head[u]; ~i; i=ed[i].nex){
            int v = ed[i].to;
            in[v]--;
            if (in[v] == 0){
                q.push(v);
                vis[v] = 1;
            }
        }
    }
    int tag = 1;
    for(int i=1; i<=n; i++){
        for(int j=head[i]; ~j; j = ed[j].nex){
            if (ed[j].c) continue;
            int v = ed[j].to;
            if (vis[i] == 0 && vis[v] == 0){
                for(int k=head[v]; ~k; k=ed[k].nex){
                    int vv = ed[k].to;
                    if (vis[v] == 0 && vis[vv] == 0){
                        ed[j].c = ed[k].c ^ 1;
                        tag = 0;
                    }
                }
            }
        }
    }
    if (!tag) cout << 2 << endl;
    else cout << 1 << endl;
    for(int i=0; i<tot; i++){
        cout << ed[i].c + 1 << ' ';
    }
    cout << endl;
    return 0;
}


#include <set>
#include <map>
#include <queue>
#include <cmath>
#include <vector>
#include <stack>
#include <limits.h>
#include <cstdio>
#include <bitset>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
int Gcd(int a,int b){if (b == 0) return a; return Gcd(b , a%b);}
int Lcm(int a, int b){ return a/Gcd(a,b)*b;}
inline int read(){
    int f = 1, x = 0;char ch = getchar();
    while (ch > '9' || ch < '0'){if (ch == '-')f = -f;ch = getchar();}
    while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}
const int maxn = 1e5 + 10;
struct edge{
    int to,nex,id;
    int c;
}ed[maxn << 1];
int head[maxn],tot;
int in[maxn];
int vis[maxn];
int color[maxn];
void add(int u,int v,int id){
    ed[tot] = (edge){v,head[u]};
    ed[tot].id = id;
    head[u] = tot++;
}
int tag = 0;
void dfs(int u,int c){
    vis[u] = 1;
    for(int i=head[u]; ~i; i = ed[i].nex){
        int v = ed[i].to;
        if (vis[v] == 0){
            color[ed[i].id] = c;
            int tag = 0;
            for(int j=head[v]; ~j; j=ed[j].nex){
                int vv = ed[j].to;
                if (vis[vv] == 0) tag = 1;
            }
            if (tag == 0) color[ed[i].id] = c^1;
            dfs(v,c);
        }
    }
}
queue<int> q;
int main(){
    int n = read(),m = read();
    memset(head,-1,sizeof(head));
    for(int i=1; i<=m; i++){
        int u = read(),v = read();
        add(u,v,i);
        in[v]++;
    }
    for(int i=1; i<=n; i++){
        if (in[i] == 0) {
            vis[i] = 1;
            q.push(i);
        }
    }
    while(!q.empty()){
        int u = q.front(); q.pop();
        for(int i=head[u]; ~i; i=ed[i].nex){
            int v = ed[i].to;
            in[v]--;
            if (in[v] == 0){
                q.push(v);
                vis[v] = 1;
            }
        }
    }
    int tag = 1;
    for(int i=1; i<=n; i++){
        if (vis[i] == 0){
            tag = 0;
            dfs(i,0);
        }
    }
    if (!tag) cout << 2 << endl;
    else cout << 1 << endl;
    for(int i=1; i<=m; i++){
        cout << color[i] + 1 << ' ';
    }
    cout << endl;
    return 0;
}


#include <set>
#include <map>
#include <queue>
#include <cmath>
#include <vector>
#include <stack>
#include <limits.h>
#include <cstdio>
#include <bitset>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
int Gcd(int a,int b){if (b == 0) return a; return Gcd(b , a%b);}
int Lcm(int a, int b){ return a/Gcd(a,b)*b;}
inline int read(){
    int f = 1, x = 0;char ch = getchar();
    while (ch > '9' || ch < '0'){if (ch == '-')f = -f;ch = getchar();}
    while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}
const int maxn = 1e5 + 10;
struct edge{
    int to,nex,c;
}ed[maxn << 1];
int head[maxn],tot;
int in[maxn];
int vis[maxn];
void add(int u,int v){
    ed[tot] = (edge){v,head[u]};
    head[u] = tot++;
}
int tag = 0;
int main(){
    int n = read(),m = read();
    memset(head,-1,sizeof(head));
    for(int i=1; i<=m; i++){
        int u = read(),v = read();
        add(u,v);
        in[v]++;
    }
    queue<int> q;
    for(int i=1; i<=n; i++){
        if (in[i] == 0) {
            vis[i] = 1;
            q.push(i);
        }
    }
    while(!q.empty()){
        int u = q.front(); q.pop();
        for(int i=head[u]; ~i; i=ed[i].nex){
            int v = ed[i].to;
            in[v]--;
            if (in[v] == 0 && !vis[v]){
                q.push(v);
                vis[v] = 1;
            }
        }
    }
    int tag = 1;
    for(int i=1; i<=n; i++){
        for(int j=head[i]; ~j; j = ed[j].nex){
            if (ed[j].c) continue;
            int v = ed[j].to;
            if (vis[i] == 0 && vis[v] == 0){
                ed[j].c = rand() % 2;
            }
        }
    }
    if (!tag) cout << 2 << endl;
    else cout << 1 << endl;
    for(int i=0; i<tot; i++){
        cout << ed[i].c + 1 << ' ';
    }
    cout << endl;
    return 0;
}


//* AuThOr GaRyMr *//
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define niv vector<int>
#define LL long long
#define IT iterator
#define PB(a) push_back(a)
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define KEEP while(1)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
typedef pair<mp,mp> superpair;
int n,m;
vector<int> each[5001];
int degree[5001];
map<mp,int> index;
bool check(){
	int OK=0;
	queue<int> Q;
	rb(i,1,n) if(!degree[i]) {
		Q.push(i);
	}
	while(!Q.empty()){
		int now=Q.front();
		Q.pop();
//		cout<<now<<endl<<endl;
		OK++;
		for(auto it:each[now]){
			degree[it]--;
			if(degree[it]==0) Q.push(it);
		}
	}
	return OK==n;
}
int OK[5001]={0},res[5001];
void Dfs(int now,int color){
	OK[now]=1;
	for(auto it:each[now]){
		res[index[II(now,it)]]=color;
		if(!OK[it]){
			Dfs(it,color^1);
		}
	}
}
int main(){
	cin>>n>>m;
	rep(i,m) {
		int u,v;
		scanf("%d %d",&u,&v);
		index[II(u,v)]=i;
		each[u].PB(v);
		degree[v]++;
	}
	if(check()){
		puts("1");
		rep(i,m) printf("1 ");
	}
	else{
		puts("2");
		rb(i,1,n)
		if(!OK[i])
		Dfs(1,0);
		rep(i,n) printf("%d ",res[i]+1);

	}
	return 0;
}


//* AuThOr GaRyMr *//
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define niv vector<int>
#define LL long long
#define IT iterator
#define PB(a) push_back(a)
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define KEEP while(1)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
typedef pair<mp,mp> superpair;
int n,m;
vector<int> each[5001];
int degree[5001];
map<mp,int> index;
bool check(){
	int OK=0;
	queue<int> Q;
	rb(i,1,n) if(!degree[i]) {
		Q.push(i);
	}
	while(!Q.empty()){
		int now=Q.front();
		Q.pop();
//		cout<<now<<endl<<endl;
		OK++;
		for(auto it:each[now]){
			degree[it]--;
			if(degree[it]==0) Q.push(it);
		}
	}
	return OK==n;
}
int OK[5001]={0},res[5001];
void Dfs(int now){
	OK[now]=1;
	for(auto it:each[now]){
		res[index[II(now,it)]]=1;
		if(!OK[it]){
			res[index[II(now,it)]]=0;
			Dfs(it);
		}
	}
}
int main(){
	cin>>n>>m;
	rep(i,m) {
		int u,v;
		scanf("%d %d",&u,&v);
		index[II(u,v)]=i;
		each[u].PB(v);
		degree[v]++;
	}
	if(check()){
		puts("1");
		rep(i,m) printf("1 ");
	}
	else{
		puts("2");
		rb(i,1,n)
		if(!OK[i])
		Dfs(i);
		rep(i,n) printf("%d ",res[i]+1);
	}
	return 0;
}


//* AuThOr GaRyMr *//
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define niv vector<int>
#define LL long long
#define IT iterator
#define PB(a) push_back(a)
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define KEEP while(1)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
typedef pair<mp,mp> superpair;
int n,m;
vector<int> each[5001];
int degree[5001];
int OK[5001]={0};
int res[5001]={0};
map<mp,int> index;
bool check(){
	int OK=0;
	queue<int> Q;
	rb(i,1,n) if(!degree[i]) {
		Q.push(i);
	}
	while(!Q.empty()){
		int now=Q.front();
		Q.pop();
		OK++;
		for(auto it:each[now]){
			degree[it]--;
			if(degree[it]==0) Q.push(it);
		}
	}
	return OK==n;
}
void Dfs(int now){
	OK[now]=1;
	for(auto it:each[now]){
		if(!OK[it]) Dfs(it);
		else
		{
			if(OK[it]==2) continue;
			res[index[II(now,it)]]=1;
		}
	}
	OK[now]=2;
}
int main(){
	cin>>n>>m;
	rep(i,m) {
		int u,v;
		scanf("%d %d",&u,&v);
		index[II(u,v)]=i;
		each[u].PB(v);
		degree[v]++;
	}
	if(check()){
		puts("1");
		rep(i,m) printf("1 ");
	}
	else{
		puts("2");
		int is=0;
		rb(i,1,n)
		if(!OK[i])
		Dfs(i);
		rep(i,m) printf("%d ",res[i]+1);
	}
	return 0;
}


//* AuThOr GaRyMr *//
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define niv vector<int>
#define LL long long
#define IT iterator
#define PB(a) push_back(a)
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define KEEP while(1)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
typedef pair<mp,mp> superpair;
int n,m;
vector<int> each[5001];
int degree[5001];
int OK[5001]={0};
int res[5001]={0};
map<mp,int> index;
bool check(){
	int OK=0;
	queue<int> Q;
	rb(i,1,n) if(!degree[i]) {
		Q.push(i);
	}
	while(!Q.empty()){
		int now=Q.front();
		Q.pop();
		OK++;
		for(auto it:each[now]){
			degree[it]--;
			if(degree[it]==0) Q.push(it);
		}
	}
	return OK==n;
}
void Dfs(int now){
	OK[now]=1;
	for(auto it:each[now]){
		if(!OK[it]) Dfs(it);
		else
		{
			if(OK[it]==2) continue;
			res[index[II(now,it)]]=1;
		}
	}
	OK[now]=2;
}
int main(){
	cin>>n>>m;
	rep(i,m) {
		int u,v;
		scanf("%d %d",&u,&v);
		index[II(u,v)]=i;
		each[u].PB(v);
		degree[v]++;
	}
	if(check()){
		puts("1");
		rep(i,m) printf("1 ");
	}
	else{
		puts("2");
		int is=0;
		rb(i,1,n)
		if(!OK[i])
		Dfs(i);
		rep(i,n) printf("%d ",res[i]+1);
	}
	return 0;
}


//* AuThOr GaRyMr *//
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define niv vector<int>
#define LL long long
#define IT iterator
#define PB(a) push_back(a)
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define KEEP while(1)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
typedef pair<mp,mp> superpair;
int n,m;
vector<int> each[5001];
int degree[5001];
int OK[5001]={0};
int res[5001]={0};
map<mp,int> index;
bool check(){
	int OK=0;
	queue<int> Q;
	rb(i,1,n) if(!degree[i]) {
		Q.push(i);
	}
	while(!Q.empty()){
		int now=Q.front();
		Q.pop();
		OK++;
		for(auto it:each[now]){
			degree[it]--;
			if(degree[it]==0) Q.push(it);
		}
	}
	return OK==n;
}
void Dfs(int now){
	OK[now]=1;
	for(auto it:each[now]){
		if(!OK[it]) Dfs(it);
		else{
			res[index[II(now,it)]]=1;
		}
	}
}
int main(){
	cin>>n>>m;
	rep(i,m) {
		int u,v;
		scanf("%d %d",&u,&v);
		index[II(u,v)]=i;
		each[u].PB(v);
		degree[v]++;
	}
	if(check()){
		puts("1");
		rep(i,m) printf("1 ");
	}
	else{
		puts("2");
		int is=0;
		rb(i,1,n)
		if(!OK[i])
		Dfs(1);
		rep(i,n) printf("%d ",res[i]+1);
	}
	return 0;
}


//* AuThOr GaRyMr *//
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define niv vector<int>
#define LL long long
#define IT iterator
#define PB(a) push_back(a)
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define KEEP while(1)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
typedef pair<mp,mp> superpair;
int n,m;
vector<int> each[5001];
int degree[5001];
int OK[5001]={0};
int res[5001]={0};
map<mp,int> index;
bool check(){
	int OK=0;
	queue<int> Q;
	rb(i,1,n) if(!degree[i]) {
		Q.push(i);
	}
	while(!Q.empty()){
		int now=Q.front();
		Q.pop();
		OK++;
		for(auto it:each[now]){
			degree[it]--;
			if(degree[it]==0) Q.push(it);
		}
	}
	return OK==n;
}
void Dfs(int now){
	OK[now]=1;
	for(auto it:each[now]){
		if(!OK[it]) Dfs(it);
		else
		{
			if(OK[it]==2) continue;
			res[index[II(now,it)]]=1;
		}
	}
	OK[now]=2;
}
int main(){
	cin>>n>>m;
	rep(i,m) {
		int u,v;
		scanf("%d %d",&u,&v);
		index[II(u,v)]=i;
		each[u].PB(v);
		degree[v]++;
	}
	if(check()){
		puts("1");
		rep(i,m) printf("1 ");
	}
	else{
		puts("2");
		int is=0;
		rb(i,1,n)
		if(!OK[i])
		Dfs(1);
		rep(i,n) printf("%d ",res[i]+1);
	}
	return 0;
}


//* AuThOr GaRyMr *//
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define niv vector<int>
#define LL long long
#define IT iterator
#define PB(a) push_back(a)
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define KEEP while(1)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
typedef pair<mp,mp> superpair;
int n,m;
vector<int> each[5001];
int degree[5001];
map<mp,int> index;
bool check(){
	int OK=0;
	queue<int> Q;
	rb(i,1,n) if(!degree[i]) {
		Q.push(i);
	}
	while(!Q.empty()){
		int now=Q.front();
		Q.pop();
//		cout<<now<<endl<<endl;
		OK++;
		for(auto it:each[now]){
			degree[it]--;
			if(degree[it]==0) Q.push(it);
		}
	}
	return OK==n;
}
int OK[5001]={0},res[5001];
void Dfs(int now,int color){
	OK[now]=1;
	for(auto it:each[now]){
		res[index[II(now,it)]]=color;
		if(!OK[it]) {
			Dfs(it,color^1);
		}
	}
}
int main(){
	cin>>n>>m;
	rep(i,m) {
		int u,v;
		scanf("%d %d",&u,&v);
		index[II(u,v)]=i;
		each[u].PB(v);
		degree[v]++;
	}
	if(check()){
		puts("1");
		rep(i,m) printf("1 ");
	}
	else{
		puts("2");
		Dfs(1,0);
		rep(i,n) printf("%d ",res[i]+1);
	}
	return 0;
}


//* AuThOr GaRyMr *//
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define niv vector<int>
#define LL long long
#define IT iterator
#define PB(a) push_back(a)
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define KEEP while(1)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
typedef pair<mp,mp> superpair;
int n,m;
vector<int> each[5001];
int degree[5001];
map<mp,int> index;
bool check(){
	int OK=0;
	queue<int> Q;
	rb(i,1,n) if(!degree[i]) {
		Q.push(i);
	}
	while(!Q.empty()){
		int now=Q.front();
		Q.pop();
//		cout<<now<<endl<<endl;
		OK++;
		for(auto it:each[now]){
			degree[it]--;
			if(degree[it]==0) Q.push(it);
		}
	}
	return OK==n;
}
int OK[5001]={0},res[5001];
void Dfs(int now,int color){
	OK[now]=1;
	for(auto it:each[now]){
		res[index[II(now,it)]]=color;
		if(!OK[it]){
			Dfs(it,color^1);
		}
	}
}
int main(){
	cin>>n>>m;
	rep(i,m) {
		int u,v;
		scanf("%d %d",&u,&v);
		index[II(u,v)]=i;
		each[u].PB(v);
		degree[v]++;
	}
	if(check()){
		puts("1");
		rep(i,m) printf("1 ");
	}
	else{
		puts("2");
		rb(i,1,n)
		if(!OK[i])
		Dfs(i,0);
		rep(i,n) printf("%d ",res[i]+1);

	}
	return 0;
}


//* AuThOr GaRyMr *//
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define niv vector<int>
#define LL long long
#define IT iterator
#define PB(a) push_back(a)
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define KEEP while(1)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
typedef pair<mp,mp> superpair;
int a[5001],b[5001],v[5001],OK=1;
vector<int> each[5001];
void Dfs(int now){
	if(!OK) return;
	v[now]=1;
	for(auto it:each[now]) {
	if(v[it]==1)
	{
		OK=0;
		return ;
	}
	else{
		if(!v[it]) Dfs(it);
	}
	}
	v[now]=2;
}
int main(){
	int n,m;
	cin>>n>>m;
	rep(i,m) scanf("%d %d",&a[i],&b[i]),each[a[i]].PB(b[i]);
	rep(i,n) if(!v[i]) Dfs(i);
	if(OK){
		puts("1");
		rep(i,m) printf("1 ");
	}
	else
	{
		puts("2");
		rep(i,m) cout<<(a[i]<b[i]? 1:2)<<" ";
	}
	return 0;
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;

vector<pii> graph[5001];
int ans[5000], col[5001], mx;

void dfs(int v)
{
    col[v] = 1;
    for (pii u: graph[v]) {
        if (col[u.first] == 0)
            dfs(u.first);
        ans[u.second] = (col[u.first] & 1) + 1;
        mx = max(mx, ans[u.second]);
    }
    col[v] = 2;
}

int main()
{
    //freopen("input.txt", "r", stdin);
    ios::sync_with_stdio(false);
    cin.tie(0);

    int n, m;
    cin >> n >> m;
    int x, y;
    for (int i = 0; i < m; i++) {
        cin >> x >> y;
        graph[x].push_back({y, i});
    }
    for (int i = 0; i < n; i++) {
        if (col[i] == 0)
            dfs(i);
    }
    cout << mx << "\n";
    for (int i = 0; i < n; i++)
        cout << ans[i] << " ";

    return 0;
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;

vector<pii> graph[5001];
int ans[5000], col[5001], mx;

void dfs(int v)
{
    col[v] = 1;
    for (pii u: graph[v]) {
        if (col[u.first] == 0)
            dfs(u.first);
        ans[u.second] = (col[u.first] & 1) + 1;
        mx = max(mx, ans[u.second]);
    }
    col[v] = 2;
}

int main()
{
    //freopen("input.txt", "r", stdin);
    ios::sync_with_stdio(false);
    cin.tie(0);

    int n, m;
    cin >> n >> m;
    int x, y;
    for (int i = 0; i < m; i++) {
        cin >> x >> y;
        graph[x].push_back({y, i});
    }
    for (int i = 1; i <= n; i++) {
        if (col[i] == 0)
            dfs(i);
    }
    cout << mx << "\n";
    for (int i = 0; i < m; i++)
        cout << ans[i] << " ";

    return 0;
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;

int ans[5000], col[5000];
vector<pii> graph[5000];

void dfs(int v)
{
    col[v] = 1;
    for (pii e: graph[v]) {
        int u = e.first, i = e.second;
        if (col[u] == 1)
            ans[i] = 2;
        else
            ans[i] = 1;
        if (col[u] == 0)
            dfs(u);
    }
    col[v] = 2;
}

int main()
{
    //freopen("input.txt", "r", stdin);
    //freopen("districts.out", "w", stdout);
    ios::sync_with_stdio(false);
    cin.tie(0);

    int n, m;
    cin >> n >> m;
    for (int i = 0; i < m; i++) {
        int x, y;
        cin >> x >> y;
        --x; --y;
        graph[x].emplace_back(y, i);
    }
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) col[j] = 0;
        dfs(i);
    }
    cout << *max_element(ans, ans + m) << "\n";
    copy(ans, ans + m, ostream_iterator<int>(cout, " "));

    return 0;
}


#include <bits/stdc++.h>
using namespace std;

typedef pair<int,int> pii;
vector<int> gra[5001],
            rev[5001];
bool used[5001], used1[5001];
vector<int> order;
set<int> comp;
vector<pii> graph[5001];
int ans[5000], cnt;

void dfs1(int v)
{
    used[v] = true;
    for (int u: gra[v]) {
        if (!used[u])
            dfs1(u);
    }
    order.push_back(v);
}

void dfs2(int v)
{
    used[v] = true;
    comp.insert(v);
    for (int u: rev[v]) {
        if (!used[u])
            dfs2(u);
    }
}

void dfs(int v, int d = 0)
{
    used1[v] = true;
    for (pii e: graph[v]) {
        int u = e.first, i = e.second;
        if (comp.count(u) && !used1[u]) {
            ans[i] = d;
            ++cnt;
            dfs(u, d ^ 1);
        }
    }
}

int main()
{
    //freopen("input.txt", "r", stdin);
    ios::sync_with_stdio(false);
    cin.tie(0);

    int n, m;
    cin >> n >> m;
    for (int i = 0; i < m; i++) {
        int x, y;
        cin >> x >> y;
        gra[x].push_back(y);
        rev[y].push_back(x);
        graph[x].push_back({y, i});
    }
    for (int i = 1; i <= n; i++)
        if (!used[i])
            dfs1(i);
    for (int i = 1; i <= n; i++)
        used[i] = false;
    reverse(order.begin(), order.end());

    for (int u: order) {
        if (!used[u]) {
            dfs2(u);
            dfs(u);
            comp.clear();
        }
    }

    if (cnt > 0)
        cout << "2\n";
    else
        cout << "1\n";
    for (int i = 0; i < m; i++)
        cout << ans[i]+1 << " ";

    return 0;
}
// 272472LF


#include <bits/stdc++.h>
using namespace std;

typedef pair<int,int> pii;
vector<int> gra[5001],
            rev[5001];
bool used[5001], used1[5001];
vector<int> order;
set<int> comp;
vector<pii> graph[5001];
int ans[5000], cnt;

void dfs1(int v)
{
    used[v] = true;
    for (int u: gra[v]) {
        if (!used[u])
            dfs1(u);
    }
    order.push_back(v);
}

void dfs2(int v)
{
    used[v] = true;
    comp.insert(v);
    for (int u: rev[v]) {
        if (!used[u])
            dfs2(u);
    }
}

void dfs(int v, int d = 0)
{
    used1[v] = true;
    for (pii e: graph[v]) {
        int u = e.first, i = e.second;
        if (comp.count(u) && !used1[u]) {
            ans[i] = d ^ 1;
            ++cnt;
            dfs(u, d);
        }
    }
}

int main()
{
    //freopen("input.txt", "r", stdin);
    ios::sync_with_stdio(false);
    cin.tie(0);

    int n, m;
    cin >> n >> m;
    for (int i = 0; i < m; i++) {
        int x, y;
        cin >> x >> y;
        gra[x].push_back(y);
        rev[y].push_back(x);
        graph[x].push_back({y, i});
    }
    for (int i = 1; i <= n; i++)
        if (!used[i])
            dfs1(i);
    for (int i = 1; i <= n; i++)
        used[i] = false;
    reverse(order.begin(), order.end());

    for (int u: order) {
        if (!used[u]) {
            dfs2(u);
            dfs(u);
            comp.clear();
        }
    }

    if (cnt > 0)
        cout << "2\n";
    else
        cout << "1\n";
    for (int i = 0; i < m; i++)
        cout << ans[i]+1 << " ";

    return 0;
}
// 272472LF


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;

vector<pii> graph[5001];
int ans[5000], col[5001], mx;

void dfs(int v)
{
    col[v] = 1;
    for (pii u: graph[v]) {
        if (col[u.first] == 0)
            dfs(u.first);
        ans[u.second] = (col[u.first] & 1) + 1;
        mx = max(mx, ans[u.second]);
    }
    col[v] = 2;
}

int main()
{
    //freopen("input.txt", "r", stdin);
    ios::sync_with_stdio(false);
    cin.tie(0);

    int n, m;
    cin >> n >> m;
    int x, y;
    for (int i = 0; i < m; i++) {
        cin >> x >> y;
        graph[x].push_back({y, i});
    }
    for (int i = 0; i < n; i++) {
        if (col[i] == 0)
            dfs(i);
    }
    cout << mx << "\n";
    for (int i = 0; i < m; i++)
        cout << ans[i] << " ";

    return 0;
}


#include <bits/stdc++.h>
using namespace std;

typedef pair<int,int> pii;
vector<int> gra[5001],
            rev[5001];
bool used[5001], used1[5001];
vector<int> order;
set<int> comp;
vector<pii> graph[5001];
int ans[5000], cnt;

void dfs1(int v)
{
    used[v] = true;
    for (int u: gra[v]) {
        if (!used[u])
            dfs1(u);
    }
    order.push_back(v);
}

void dfs2(int v)
{
    used[v] = true;
    comp.insert(v);
    for (int u: rev[v]) {
        if (!used[u])
            dfs2(u);
    }
}

void dfs(int v, int d = 0)
{
    used1[v] = true;
    for (pii e: graph[v]) {
        int u = e.first, i = e.second;
        if (comp.count(u)) {
            ans[i] = d;
            ++cnt;
            if (!used1[u])
                dfs(u, d ^ 1);
        }
    }
}

int main()
{
    //freopen("input.txt", "r", stdin);
    ios::sync_with_stdio(false);
    cin.tie(0);

    int n, m;
    cin >> n >> m;
    for (int i = 0; i < m; i++) {
        int x, y;
        cin >> x >> y;
        gra[x].push_back(y);
        rev[y].push_back(x);
        graph[x].push_back({y, i});
    }
    for (int i = 1; i <= n; i++)
        if (!used[i])
            dfs1(i);
    for (int i = 1; i <= n; i++)
        used[i] = false;
    reverse(order.begin(), order.end());

    for (int u: order) {
        if (!used[u]) {
            dfs2(u);
            dfs(u);
            comp.clear();
        }
    }

    if (cnt > 0)
        cout << "2\n";
    else
        cout << "1\n";
    for (int i = 0; i < m; i++)
        cout << ans[i]+1 << " ";

    return 0;
}
// 272472LF


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<ll, ll > pll;
typedef vector<pll > vpll;
typedef vector<ll> vll;
//========================================================================================================//
#define rep(i,a,b) for(i=a;i<b;i++)
#define repr(i,a,b) for(i=a;i>=b;i--)
//========================================================================================================//
#define lb lower_bound
#define ub upper_bound
#define F first
#define S second
#define pb push_back
#define mp make_pair
#define popb  pop_back
#define mem(a,b) memset(a,b,sizeof(a))
#define sz size()
#define M 1000000007
#define PI 3.14159265

class Graph {
    int V; // No. of vertices'

    // Pointer to an array containing adjacency lisr
    list<int>* adj;

public:
    Graph(int V); // Constructor

    // function to add an edge to graph
    void addEdge(int u, int v);

    // Returns true if there is a cycle in the graph
    // else false.
    bool isCycle();
};

Graph::Graph(int V)
{
    this->V = V;
    adj = new list<int>[V];
}

void Graph::addEdge(int u, int v)
{
    adj[u].push_back(v);
}

// This function returns true if there is a cycle
// in directed graph, else returns false.
bool Graph::isCycle()
{
    // Create a vector to store indegrees of all
    // vertices. Initialize all indegrees as 0.
    vector<int> in_degree(V, 0);

    // Traverse adjacency lists to fill indegrees of
    // vertices. This step takes O(V+E) time
    for (int u = 0; u < V; u++) {
        for (auto v : adj[u])
            in_degree[v]++;
    }

    // Create an queue and enqueue all vertices with
    // indegree 0
    queue<int> q;
    for (int i = 0; i < V; i++)
        if (in_degree[i] == 0)
            q.push(i);

    // Initialize count of visited vertices
    int cnt = 0;

    // Create a vector to store result (A topological
    // ordering of the vertices)
    vector<int> top_order;

    // One by one dequeue vertices from queue and enqueue
    // adjacents if indegree of adjacent becomes 0
    while (!q.empty()) {

        // Extract front of queue (or perform dequeue)
        // and add it to topological order
        int u = q.front();
        q.pop();
        top_order.push_back(u);

        // Iterate through all its neighbouring nodes
        // of dequeued node u and decrease their in-degree
        // by 1
        list<int>::iterator itr;
        for (itr = adj[u].begin(); itr != adj[u].end(); itr++)

            // If in-degree becomes zero, add it to queue
            if (--in_degree[*itr] == 0)
                q.push(*itr);

        cnt++;
    }

    // Check if there was a cycle
    if (cnt != V)
        return true;
    else
        return false;
}

// Driver program to test above functions
int main()
{
    // Create a graph given in the above diagram
    int n,m,i;
    cin>>n>>m;

    Graph g(n);
    vector<vector<int>> eg(5001);
    vector<pair<int,int>> vp;
    rep(i,0,m)
    {
        int x,y;
        cin>>x>>y;
        x--;
        y--;
       // cin>>x>>y;
        g.addEdge(x,y);
        eg[x].push_back(y);
        eg[y].push_back(x);
        vp.push_back(make_pair(x,y));
        //vp.push_back(make_pair(y,x));
    }
    map<pair<int,int>,int> mpp;
    if (g.isCycle())
    {
        bool vis[n];
        rep(i,0,n)
            vis[i]=false;
        int ar[n],j;

        rep(j,0,n)
        {

            if(vis[j])
                continue;
            ar[j]=1;
            queue<int> q;
            q.push(j);
            int co=0;

            while(!q.empty())
            {
                int x=q.front();
                q.pop();
        //cout<<x<<endl;
                if(vis[x])
                    continue;
                vis[x]=true;
                rep(i,0,eg[x].size())
                {
                    int y=eg[x][i];
                    ar[y]=(ar[x]+1)%2;
                    if(ar[y]==0)
                        ar[y]=2;
                    q.push(ar[y]);
                }
            }

        }
                cout<<2<<endl;
        rep(i,0,vp.size())
            cout<<ar[vp[i].F]<<" ";
    }
    else
    {
        cout<<1<<" ";
        rep(i,0,m)
            cout<<1<<" ";
    }
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<ll, ll > pll;
typedef vector<pll > vpll;
typedef vector<ll> vll;
//========================================================================================================//
#define rep(i,a,b) for(i=a;i<b;i++)
#define repr(i,a,b) for(i=a;i>=b;i--)
//========================================================================================================//
#define lb lower_bound
#define ub upper_bound
#define F first
#define S second
#define pb push_back
#define mp make_pair
#define popb  pop_back
#define mem(a,b) memset(a,b,sizeof(a))
#define sz size()
#define M 1000000007
#define PI 3.14159265

class Graph {
    int V; // No. of vertices'

    // Pointer to an array containing adjacency lisr
    list<int>* adj;

public:
    Graph(int V); // Constructor

    // function to add an edge to graph
    void addEdge(int u, int v);

    // Returns true if there is a cycle in the graph
    // else false.
    bool isCycle();
};

Graph::Graph(int V)
{
    this->V = V;
    adj = new list<int>[V];
}

void Graph::addEdge(int u, int v)
{
    adj[u].push_back(v);
}

// This function returns true if there is a cycle
// in directed graph, else returns false.
bool Graph::isCycle()
{
    // Create a vector to store indegrees of all
    // vertices. Initialize all indegrees as 0.
    vector<int> in_degree(V, 0);

    // Traverse adjacency lists to fill indegrees of
    // vertices. This step takes O(V+E) time
    for (int u = 0; u < V; u++) {
        for (auto v : adj[u])
            in_degree[v]++;
    }

    // Create an queue and enqueue all vertices with
    // indegree 0
    queue<int> q;
    for (int i = 0; i < V; i++)
        if (in_degree[i] == 0)
            q.push(i);

    // Initialize count of visited vertices
    int cnt = 0;

    // Create a vector to store result (A topological
    // ordering of the vertices)
    vector<int> top_order;

    // One by one dequeue vertices from queue and enqueue
    // adjacents if indegree of adjacent becomes 0
    while (!q.empty()) {

        // Extract front of queue (or perform dequeue)
        // and add it to topological order
        int u = q.front();
        q.pop();
        top_order.push_back(u);

        // Iterate through all its neighbouring nodes
        // of dequeued node u and decrease their in-degree
        // by 1
        list<int>::iterator itr;
        for (itr = adj[u].begin(); itr != adj[u].end(); itr++)

            // If in-degree becomes zero, add it to queue
            if (--in_degree[*itr] == 0)
                q.push(*itr);

        cnt++;
    }

    // Check if there was a cycle
    if (cnt != V)
        return true;
    else
        return false;
}

// Driver program to test above functions
int main()
{
    // Create a graph given in the above diagram
    int n,m,i;
    cin>>n>>m;

    Graph g(n);
    vector<vector<int>> eg(5001);
    vector<pair<int,int>> vp;
    rep(i,0,m)
    {
        int x,y;
        cin>>x>>y;
        x--;
        y--;
       // cin>>x>>y;
        g.addEdge(x,y);
        eg[x].push_back(y);
        vp.push_back(make_pair(x,y));
        vp.push_back(make_pair(y,x));
    }
    map<pair<int,int>,int> mpp;
    if (g.isCycle())
    {
        bool vis[n];
        rep(i,0,n)
            vis[i]=false;
        int ar[n],j;

        rep(j,0,n)
        {

            if(vis[j])
                continue;
            ar[j]=1;
            queue<int> q;
            q.push(j);
            int co=0;

            while(!q.empty())
            {
                int x=q.front();
                q.pop();
        //cout<<x<<endl;
                if(vis[x])
                    continue;
                vis[x]=true;
                rep(i,0,eg[x].size())
                {
                    int y=eg[x][i];
                    ar[y]=(ar[x]+1)%2;
                    if(ar[y]==0)
                        ar[y]=2;
                    q.push(ar[y]);
                }
            }

        }
                cout<<2<<endl;
        rep(i,0,vp.size())
            cout<<ar[vp[i].F]<<" ";
    }
    else
    {
        cout<<1<<" ";
        rep(i,0,m)
            cout<<1<<" ";
    }
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<ll, ll > pll;
typedef vector<pll > vpll;
typedef vector<ll> vll;
//========================================================================================================//
#define rep(i,a,b) for(i=a;i<b;i++)
#define repr(i,a,b) for(i=a;i>=b;i--)
//========================================================================================================//
#define lb lower_bound
#define ub upper_bound
#define F first
#define S second
#define pb push_back
#define mp make_pair
#define popb  pop_back
#define mem(a,b) memset(a,b,sizeof(a))
#define sz size()
#define M 1000000007
#define PI 3.14159265

class Graph {
    int V; // No. of vertices'

    // Pointer to an array containing adjacency lisr
    list<int>* adj;

public:
    Graph(int V); // Constructor

    // function to add an edge to graph
    void addEdge(int u, int v);

    // Returns true if there is a cycle in the graph
    // else false.
    bool isCycle();
};

Graph::Graph(int V)
{
    this->V = V;
    adj = new list<int>[V];
}

void Graph::addEdge(int u, int v)
{
    adj[u].push_back(v);
}

// This function returns true if there is a cycle
// in directed graph, else returns false.
bool Graph::isCycle()
{
    // Create a vector to store indegrees of all
    // vertices. Initialize all indegrees as 0.
    vector<int> in_degree(V, 0);

    // Traverse adjacency lists to fill indegrees of
    // vertices. This step takes O(V+E) time
    for (int u = 0; u < V; u++) {
        for (auto v : adj[u])
            in_degree[v]++;
    }

    // Create an queue and enqueue all vertices with
    // indegree 0
    queue<int> q;
    for (int i = 0; i < V; i++)
        if (in_degree[i] == 0)
            q.push(i);

    // Initialize count of visited vertices
    int cnt = 0;

    // Create a vector to store result (A topological
    // ordering of the vertices)
    vector<int> top_order;

    // One by one dequeue vertices from queue and enqueue
    // adjacents if indegree of adjacent becomes 0
    while (!q.empty()) {

        // Extract front of queue (or perform dequeue)
        // and add it to topological order
        int u = q.front();
        q.pop();
        top_order.push_back(u);

        // Iterate through all its neighbouring nodes
        // of dequeued node u and decrease their in-degree
        // by 1
        list<int>::iterator itr;
        for (itr = adj[u].begin(); itr != adj[u].end(); itr++)

            // If in-degree becomes zero, add it to queue
            if (--in_degree[*itr] == 0)
                q.push(*itr);

        cnt++;
    }

    // Check if there was a cycle
    if (cnt != V)
        return true;
    else
        return false;
}

// Driver program to test above functions
int main()
{
    // Create a graph given in the above diagram
    int n,m,i;
    cin>>n>>m;

    Graph g(n);
    vector<vector<int>> eg(5001);
    vector<pair<int,int>> vp;
    rep(i,0,m)
    {
        int x,y;
        cin>>x>>y;
        x--;
        y--;
       // cin>>x>>y;
        g.addEdge(x,y);
        eg[x].push_back(y);
        vp.push_back(make_pair(x,y));

    }
    map<pair<int,int>,int> mpp;
    if (g.isCycle())
    {
        queue<int> q;
        q.push(0);
        int co=0;
        int ar[n];
        rep(i,0,n)
            ar[i]=1;
        ar[0]=1;
        bool vis[n];
        rep(i,0,n)
            vis[i]=false;

        while(!q.empty())
        {
            int x=q.front();
            q.pop();
    //cout<<x<<endl;
            if(vis[x])
                continue;
            vis[x]=true;
            rep(i,0,eg[x].size())
            {
                int y=eg[x][i];
                ar[y]=(ar[x]+1)%2;
                if(ar[y]==0)
                    ar[y]=2;
                q.push(ar[y]);
            }
        }
        cout<<2<<endl;
        rep(i,0,vp.size())
            cout<<ar[vp[i].F]<<" ";
    }
    else
    {
        cout<<1<<" ";
        rep(i,0,m)
            cout<<1<<" ";
    }
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<ll, ll > pll;
typedef vector<pll > vpll;
typedef vector<ll> vll;
//========================================================================================================//
#define rep(i,a,b) for(i=a;i<b;i++)
#define repr(i,a,b) for(i=a;i>=b;i--)
//========================================================================================================//
#define lb lower_bound
#define ub upper_bound
#define F first
#define S second
#define pb push_back
#define mp make_pair
#define popb  pop_back
#define mem(a,b) memset(a,b,sizeof(a))
#define sz size()
#define M 1000000007
#define PI 3.14159265

class Graph {
    int V; // No. of vertices'

    // Pointer to an array containing adjacency lisr
    list<int>* adj;

public:
    Graph(int V); // Constructor

    // function to add an edge to graph
    void addEdge(int u, int v);

    // Returns true if there is a cycle in the graph
    // else false.
    bool isCycle();
};

Graph::Graph(int V)
{
    this->V = V;
    adj = new list<int>[V];
}

void Graph::addEdge(int u, int v)
{
    adj[u].push_back(v);
}

// This function returns true if there is a cycle
// in directed graph, else returns false.
bool Graph::isCycle()
{
    // Create a vector to store indegrees of all
    // vertices. Initialize all indegrees as 0.
    vector<int> in_degree(V, 0);

    // Traverse adjacency lists to fill indegrees of
    // vertices. This step takes O(V+E) time
    for (int u = 0; u < V; u++) {
        for (auto v : adj[u])
            in_degree[v]++;
    }

    // Create an queue and enqueue all vertices with
    // indegree 0
    queue<int> q;
    for (int i = 0; i < V; i++)
        if (in_degree[i] == 0)
            q.push(i);

    // Initialize count of visited vertices
    int cnt = 0;

    // Create a vector to store result (A topological
    // ordering of the vertices)
    vector<int> top_order;

    // One by one dequeue vertices from queue and enqueue
    // adjacents if indegree of adjacent becomes 0
    while (!q.empty()) {

        // Extract front of queue (or perform dequeue)
        // and add it to topological order
        int u = q.front();
        q.pop();
        top_order.push_back(u);

        // Iterate through all its neighbouring nodes
        // of dequeued node u and decrease their in-degree
        // by 1
        list<int>::iterator itr;
        for (itr = adj[u].begin(); itr != adj[u].end(); itr++)

            // If in-degree becomes zero, add it to queue
            if (--in_degree[*itr] == 0)
                q.push(*itr);

        cnt++;
    }

    // Check if there was a cycle
    if (cnt != V)
        return true;
    else
        return false;
}

// Driver program to test above functions
int main()
{
    // Create a graph given in the above diagram
    int n,m,i;
    cin>>n>>m;

    Graph g(n);
    vector<vector<int>> eg(5001);
    vector<pair<int,int>> vp;
    rep(i,0,m)
    {
        int x,y;
        cin>>x>>y;
        x--;
        y--;
       // cin>>x>>y;
        g.addEdge(x,y);
        eg[x].push_back(y);
        vp.push_back(make_pair(x,y));

    }
    map<pair<int,int>,int> mpp;
    if (g.isCycle())
    {
        bool vis[n];
        rep(i,0,n)
            vis[i]=false;
        int ar[n],j;

        rep(j,0,n)
        {
            if(vis[j])
                continue;
            queue<int> q;
            q.push(j);
            int co=0;

            while(!q.empty())
            {
                int x=q.front();
                q.pop();
        //cout<<x<<endl;
                if(vis[x])
                    continue;
                vis[x]=true;
                rep(i,0,eg[x].size())
                {
                    int y=eg[x][i];
                    ar[y]=(ar[x]+1)%2;
                    if(ar[y]==0)
                        ar[y]=2;
                    q.push(ar[y]);
                }
            }

        }
                cout<<2<<endl;
        rep(i,0,vp.size())
            cout<<ar[vp[i].F]<<" ";
    }
    else
    {
        cout<<1<<" ";
        rep(i,0,m)
            cout<<1<<" ";
    }
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<ll, ll > pll;
typedef vector<pll > vpll;
typedef vector<ll> vll;
//========================================================================================================//
#define rep(i,a,b) for(i=a;i<b;i++)
#define repr(i,a,b) for(i=a;i>=b;i--)
//========================================================================================================//
#define lb lower_bound
#define ub upper_bound
#define F first
#define S second
#define pb push_back
#define mp make_pair
#define popb  pop_back
#define mem(a,b) memset(a,b,sizeof(a))
#define sz size()
#define M 1000000007
#define PI 3.14159265

class Graph {
    int V; // No. of vertices'

    // Pointer to an array containing adjacency lisr
    list<int>* adj;

public:
    Graph(int V); // Constructor

    // function to add an edge to graph
    void addEdge(int u, int v);

    // Returns true if there is a cycle in the graph
    // else false.
    bool isCycle();
};

Graph::Graph(int V)
{
    this->V = V;
    adj = new list<int>[V];
}

void Graph::addEdge(int u, int v)
{
    adj[u].push_back(v);
}

// This function returns true if there is a cycle
// in directed graph, else returns false.
bool Graph::isCycle()
{
    // Create a vector to store indegrees of all
    // vertices. Initialize all indegrees as 0.
    vector<int> in_degree(V, 0);

    // Traverse adjacency lists to fill indegrees of
    // vertices. This step takes O(V+E) time
    for (int u = 0; u < V; u++) {
        for (auto v : adj[u])
            in_degree[v]++;
    }

    // Create an queue and enqueue all vertices with
    // indegree 0
    queue<int> q;
    for (int i = 0; i < V; i++)
        if (in_degree[i] == 0)
            q.push(i);

    // Initialize count of visited vertices
    int cnt = 0;

    // Create a vector to store result (A topological
    // ordering of the vertices)
    vector<int> top_order;

    // One by one dequeue vertices from queue and enqueue
    // adjacents if indegree of adjacent becomes 0
    while (!q.empty()) {

        // Extract front of queue (or perform dequeue)
        // and add it to topological order
        int u = q.front();
        q.pop();
        top_order.push_back(u);

        // Iterate through all its neighbouring nodes
        // of dequeued node u and decrease their in-degree
        // by 1
        list<int>::iterator itr;
        for (itr = adj[u].begin(); itr != adj[u].end(); itr++)

            // If in-degree becomes zero, add it to queue
            if (--in_degree[*itr] == 0)
                q.push(*itr);

        cnt++;
    }

    // Check if there was a cycle
    if (cnt != V)
        return true;
    else
        return false;
}

// Driver program to test above functions
int main()
{
    // Create a graph given in the above diagram
    int n,m,i;
    cin>>n>>m;

    Graph g(n);
    vector<vector<int>> eg(5001);
    vector<pair<int,int>> vp;
    rep(i,0,m)
    {
        int x,y;
        cin>>x>>y;
        x--;
        y--;
       // cin>>x>>y;
        g.addEdge(x,y);
        eg[x].push_back(y);
        vp.push_back(make_pair(x,y));

    }
    map<pair<int,int>,int> mpp;
    if (g.isCycle())
    {
        queue<int> q;
        q.push(0);
        int co=0;
        int ar[n];
        ar[0]=1;
        bool vis[n];
        rep(i,0,n)
            vis[i]=false;

        while(!q.empty())
        {
            int x=q.front();
            q.pop();
    //cout<<x<<endl;
            if(vis[x])
                continue;
            vis[x]=true;
            rep(i,0,eg[x].size())
            {
                int y=eg[x][i];
                ar[y]=(ar[x]+1)%2;
                if(ar[y]==0)
                    ar[y]=2;
                q.push(ar[y]);
            }
        }
        cout<<2<<endl;
        rep(i,0,vp.size())
            cout<<ar[vp[i].F]<<" ";
    }
    else
    {
        cout<<1<<" ";
        rep(i,0,m)
            cout<<1<<" ";
    }
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<ll, ll > pll;
typedef vector<pll > vpll;
typedef vector<ll> vll;
//========================================================================================================//
#define rep(i,a,b) for(i=a;i<b;i++)
#define repr(i,a,b) for(i=a;i>=b;i--)
//========================================================================================================//
#define lb lower_bound
#define ub upper_bound
#define F first
#define S second
#define pb push_back
#define mp make_pair
#define popb  pop_back
#define mem(a,b) memset(a,b,sizeof(a))
#define sz size()
#define M 1000000007
#define PI 3.14159265

class Graph {
    int V; // No. of vertices'

    // Pointer to an array containing adjacency lisr
    list<int>* adj;

public:
    Graph(int V); // Constructor

    // function to add an edge to graph
    void addEdge(int u, int v);

    // Returns true if there is a cycle in the graph
    // else false.
    bool isCycle();
};

Graph::Graph(int V)
{
    this->V = V;
    adj = new list<int>[V];
}

void Graph::addEdge(int u, int v)
{
    adj[u].push_back(v);
}

// This function returns true if there is a cycle
// in directed graph, else returns false.
bool Graph::isCycle()
{
    // Create a vector to store indegrees of all
    // vertices. Initialize all indegrees as 0.
    vector<int> in_degree(V, 0);

    // Traverse adjacency lists to fill indegrees of
    // vertices. This step takes O(V+E) time
    for (int u = 0; u < V; u++) {
        for (auto v : adj[u])
            in_degree[v]++;
    }

    // Create an queue and enqueue all vertices with
    // indegree 0
    queue<int> q;
    for (int i = 0; i < V; i++)
        if (in_degree[i] == 0)
            q.push(i);

    // Initialize count of visited vertices
    int cnt = 0;

    // Create a vector to store result (A topological
    // ordering of the vertices)
    vector<int> top_order;

    // One by one dequeue vertices from queue and enqueue
    // adjacents if indegree of adjacent becomes 0
    while (!q.empty()) {

        // Extract front of queue (or perform dequeue)
        // and add it to topological order
        int u = q.front();
        q.pop();
        top_order.push_back(u);

        // Iterate through all its neighbouring nodes
        // of dequeued node u and decrease their in-degree
        // by 1
        list<int>::iterator itr;
        for (itr = adj[u].begin(); itr != adj[u].end(); itr++)

            // If in-degree becomes zero, add it to queue
            if (--in_degree[*itr] == 0)
                q.push(*itr);

        cnt++;
    }

    // Check if there was a cycle
    if (cnt != V)
        return true;
    else
        return false;
}

// Driver program to test above functions
int main()
{
    // Create a graph given in the above diagram
    int n,m,i;
    cin>>n>>m;

    Graph g(n);
    vector<vector<int>> eg(5001);
    vector<pair<int,int>> vp;
    rep(i,0,m)
    {
        int x,y;
        cin>>x>>y;
        x--;
        y--;
       // cin>>x>>y;
        g.addEdge(x,y);
        eg[x].push_back(y);
        vp.push_back(make_pair(x,y));

    }
    map<pair<int,int>,int> mpp;
    if (g.isCycle())
    {

        cout<<2<<endl;
        rep(i,0,vp.size())
            if(vp[i].F>vp[i].S)
                cout<<1<<" ";
            else
                cout<<2<<" ";
    }
    else
    {
        cout<<1<<" ";
        rep(i,0,m)
            cout<<1<<" ";
    }
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<ll, ll > pll;
typedef vector<pll > vpll;
typedef vector<ll> vll;
//========================================================================================================//
#define rep(i,a,b) for(i=a;i<b;i++)
#define repr(i,a,b) for(i=a;i>=b;i--)
//========================================================================================================//
#define lb lower_bound
#define ub upper_bound
#define F first
#define S second
#define pb push_back
#define mp make_pair
#define popb  pop_back
#define mem(a,b) memset(a,b,sizeof(a))
#define sz size()
#define M 1000000007
#define PI 3.14159265

class Graph {
    int V; // No. of vertices'

    // Pointer to an array containing adjacency lisr
    list<int>* adj;

public:
    Graph(int V); // Constructor

    // function to add an edge to graph
    void addEdge(int u, int v);

    // Returns true if there is a cycle in the graph
    // else false.
    bool isCycle();
};

Graph::Graph(int V)
{
    this->V = V;
    adj = new list<int>[V];
}

void Graph::addEdge(int u, int v)
{
    adj[u].push_back(v);
}

// This function returns true if there is a cycle
// in directed graph, else returns false.
bool Graph::isCycle()
{
    // Create a vector to store indegrees of all
    // vertices. Initialize all indegrees as 0.
    vector<int> in_degree(V, 0);

    // Traverse adjacency lists to fill indegrees of
    // vertices. This step takes O(V+E) time
    for (int u = 0; u < V; u++) {
        for (auto v : adj[u])
            in_degree[v]++;
    }

    // Create an queue and enqueue all vertices with
    // indegree 0
    queue<int> q;
    for (int i = 0; i < V; i++)
        if (in_degree[i] == 0)
            q.push(i);

    // Initialize count of visited vertices
    int cnt = 0;

    // Create a vector to store result (A topological
    // ordering of the vertices)
    vector<int> top_order;

    // One by one dequeue vertices from queue and enqueue
    // adjacents if indegree of adjacent becomes 0
    while (!q.empty()) {

        // Extract front of queue (or perform dequeue)
        // and add it to topological order
        int u = q.front();
        q.pop();
        top_order.push_back(u);

        // Iterate through all its neighbouring nodes
        // of dequeued node u and decrease their in-degree
        // by 1
        list<int>::iterator itr;
        for (itr = adj[u].begin(); itr != adj[u].end(); itr++)

            // If in-degree becomes zero, add it to queue
            if (--in_degree[*itr] == 0)
                q.push(*itr);

        cnt++;
    }

    // Check if there was a cycle
    if (cnt != V)
        return true;
    else
        return false;
}

// Driver program to test above functions
int main()
{
    // Create a graph given in the above diagram
    int n,m,i;
    cin>>n>>m;

    Graph g(n);
    vector<vector<int>> eg(5001);
    vector<pair<int,int>> vp;
    rep(i,0,m)
    {
        int x,y;
        cin>>x>>y;
        x--;
        y--;
       // cin>>x>>y;
        g.addEdge(x,y);
        eg[x].push_back(y);
        vp.push_back(make_pair(x,y));

    }
    map<pair<int,int>,int> mpp;
    if (g.isCycle())
    {
        queue<int> q;
        q.push(0);
        int co=0;
        int ar[n];
        ar[0]=1;
        bool vis[n];
        rep(i,0,n)
            vis[i]=false;

        while(!q.empty())
        {
            int x=q.front();
            q.pop();
    //cout<<x<<endl;
            if(vis[x])
                continue;
            vis[x]=true;
            rep(i,0,eg[x].size())
            {
                int y=eg[x][i];
                ar[y]=(ar[x]+1)%2;
                if(ar[y]==0)
                    ar[y]=2;
                q.push(ar[y]);
            }
        }
        rep(i,0,vp.size())
            cout<<ar[vp[i].F]<<" ";
    }
    else
    {
        rep(i,0,m)
            cout<<1<<" ";
    }
    return 0;
}