#include <bits/stdc++.h>
using namespace std;
int realIndex(int x, int n)
{
if ( x < 0 )
return -x + n;
return x;
}
void printValues(vector<vector<int>>&g, int n)
{
int i;
cout << "Values: \n";
for (i = 1; i <= 2 * n; i++)
{
for (auto it : g[i])
cout << it << " ";
cout << "\n";
}
}
void computeRelation(vector<vector<int>>& g, vector<vector<int>>& gt, int x, int y, int n)
{
int real_x = realIndex(x, n);
int real_y = realIndex(y, n);
int real_non_x = realIndex(-x, n);
int real_non_y = realIndex(-y, n);
g[real_non_x].push_back(real_y);
gt[real_y].push_back(real_non_x);
g[real_non_y].push_back(real_x);
gt[real_x].push_back(real_non_y);
}
void dfs(int node, vector<int>&used, vector<vector<int>>&g, vector<int>&order)
{
used[node] = true;
for (int ngb: g[node])
{
if (!used[ngb])
dfs(ngb, used, g, order);
}
order.push_back(node);
}
void dfs_2(int node, vector<int>&used, vector<vector<int>>&g, vector<int>&act_comp)
{
used[node] = true;
act_comp.push_back(node);
for (auto ngb: g[node])
{
if (!used[ngb])
dfs_2(ngb, used, g, act_comp);
}
}
void computeTarjan(vector<vector<int>>&g, vector<vector<int>>>, vector<vector<int>>& comps, int n, vector<int>& contracted_node)
{
vector<int> used(2 * n + 1), order;
vector<int> act_comp;
for (int i = 1; i <= 2 * n; ++i)
if (!used[i])
dfs(i, used, g, order);
fill(used.begin(), used.end(), 0);
for (auto it = order.rbegin(); it != order.rend(); ++it)
if (!used[*it])
{
act_comp.clear();
dfs_2(*it, used, gt, act_comp);
// merge nodes
for (auto it : act_comp)
contracted_node[it] = comps.size();
comps.push_back(act_comp);
}
}
bool checkIfPossible(vector<int>& contracted_node, int n)
{
for (int i = 1; i <= n; i++)
{
int cnode_i = contracted_node[i];
int cnode_n = contracted_node[i + n];
if (contracted_node[i] == contracted_node[i + n])
return 0;
}
return 1;
}
void computeAssignment(vector<vector<int>>&g, vector<int>&contracted_node, int n, vector<int>& dg,
vector<vector<int>>& comps, vector<int>& value)
{
for (int node = 1; node <= 2 * n; node++)
{
for (auto ngb: g[node])
if (contracted_node[node] != contracted_node[ngb])
dg[contracted_node[ngb]]++;
}
queue<int>Q;
for (int i = 0; i < comps.size(); i++)
{
if (!dg[i])
Q.push(i);
}
while(!Q.empty())
{
int act = Q.front();
Q.pop();
for (auto node : comps[act])
{
int realVar = (node > n) ? node - n : node;
if (value[realVar] == -1)
value[realVar] = (node <= n) ? 0 : 1;
}
// decrease dg for adjacent components
for (auto node : comps[act])
{
for (auto ngb : g[node])
{
int cnode_node = contracted_node[node];
int cnode_ngb = contracted_node[ngb];
if (cnode_node != cnode_ngb)
{
dg[cnode_ngb]--;
if (!dg[cnode_ngb])
Q.push(cnode_ngb);
}
}
}
}
for (int i = 1; i <= n; ++i)
printf("%d ", value[i]);
}
int main()
{
freopen("2sat.in", "r", stdin);
freopen("2sat.out", "w", stdout);
int n, m;
scanf("%d%d", &n, &m);
vector<vector<int>>g(2 * n + 1);
vector<vector<int>>gt(2 * n + 1);
vector<int> value(n + 1, -1);
vector<vector<int>>comps;
vector<int> contracted_node(2 * n + 1);
vector<int> dg( 2 * n + 1);
for (int i = 0; i < m; i++)
{
int x, y;
scanf("%d%d", &x, &y);
computeRelation(g, gt, x, y, n);
}
// printValues(g, n);
// printValues(gt, n);
computeTarjan(g, gt, comps, n, contracted_node);
bool verdict = checkIfPossible(contracted_node, n);
if (!verdict)
{cout << -1; return 0;}
computeAssignment(g, contracted_node, n, dg, comps, value);
return 0;
}