36961e668e50cc020194e4dce1c7e43f11312c969e6b17964df33e528f8844e7
// https://szkopul.edu.pl/problemset/problem/FKqZZxq392rXuZdedx7vm5kh/site/?key=statement
#include <bits/stdc++.h>
// #define GARY_DBG
#define GARY_LIB
constexpr int sizik = 20 * 1001;
#define ar std::array
typedef std::vector<std::vector<int>> _kra;
struct Ziom {
int l, r;
};
std::vector<Ziom> ziomy;
std::vector<std::pair<int, int>> starts_at[sizik];
std::vector<std::pair<int, int>> ends_at[sizik];
namespace max_tree {
using P = std::pair<int, int>;
constexpr P NEUTRAL = {-1, -1};
P d[4 * sizik];
P op(P a, P b) {
return std::max(a, b);
}
void merge(int v) {
d[v] = op(d[2 * v], d[2 * v + 1]);
}
void init(int v, int tl, int tr) {
if (tl == tr) {
if (starts_at[tl].empty()) {
d[v] = NEUTRAL;
} else {
d[v] = starts_at[tl].back();
}
} else {
int tm = (tl + tr) / 2;
init(2 * v, tl, tm);
init(2 * v + 1, tm + 1, tr);
merge(v);
}
}
P query(int v, int tl, int tr, int l, int r) {
if (l > r) return NEUTRAL;
if (tl == l && tr == r) {
return d[v];
}
int tm = (tl + tr) / 2;
return op(query(2 * v, tl, tm, l, std::min(r, tm)), query(2 * v + 1, tm + 1, tr, std::max(l, tm + 1), r));
}
void update(int v, int tl, int tr, int pos, P val) {
if (tl == tr) {
d[v] = val;
} else {
int tm = (tl + tr) / 2;
if (pos <= tm) {
update(2 * v, tl, tm, pos, val);
} else {
update(2 * v + 1, tm + 1, tr, pos, val);
}
merge(v);
}
}
} // namespace max_tree
namespace min_tree {
using P = std::pair<int, int>;
constexpr P NEUTRAL = {2 * sizik, -1};
P d[4 * sizik];
P op(P a, P b) {
return std::min(a, b);
}
void merge(int v) {
d[v] = op(d[2 * v], d[2 * v + 1]);
}
void init(int v, int tl, int tr) {
if (tl == tr) {
if (ends_at[tl].empty()) {
d[v] = NEUTRAL;
} else {
d[v] = ends_at[tl].back();
}
} else {
int tm = (tl + tr) / 2;
init(2 * v, tl, tm);
init(2 * v + 1, tm + 1, tr);
merge(v);
}
}
P query(int v, int tl, int tr, int l, int r) {
if (l > r) return NEUTRAL;
if (tl == l && tr == r) {
return d[v];
}
int tm = (tl + tr) / 2;
return op(query(2 * v, tl, tm, l, std::min(r, tm)), query(2 * v + 1, tm + 1, tr, std::max(l, tm + 1), r));
}
void update(int v, int tl, int tr, int pos, P val) {
if (tl == tr) {
d[v] = val;
} else {
int tm = (tl + tr) / 2;
if (pos <= tm) {
update(2 * v, tl, tm, pos, val);
} else {
update(2 * v + 1, tm + 1, tr, pos, val);
}
merge(v);
}
}
} // namespace min_tree
void refresh_start(int pos, int n, const std::vector<bool>& vis) {
while (!starts_at[pos].empty() && vis[starts_at[pos].back().second]) {
starts_at[pos].pop_back();
}
max_tree::P val = starts_at[pos].empty() ? max_tree::NEUTRAL : starts_at[pos].back();
max_tree::update(1, 1, n, pos, val);
}
void refresh_end(int pos, int n, const std::vector<bool>& vis) {
while (!ends_at[pos].empty() && vis[ends_at[pos].back().second]) {
ends_at[pos].pop_back();
}
min_tree::P val = ends_at[pos].empty() ? min_tree::NEUTRAL : ends_at[pos].back();
min_tree::update(1, 1, n, pos, val);
}
void solve() {
int n, k;
std::cin >> n >> k;
ziomy.resize(k);
for (auto& [a, b] : ziomy) {
std::cin >> a >> b;
if (a > b) std::swap(a, b);
}
for (int i = 0; i < k; i++) {
starts_at[ziomy[i].l].push_back({ziomy[i].r, i});
ends_at[ziomy[i].r].push_back({ziomy[i].l, i});
}
for (int i = 1; i <= n; i++) {
std::sort(starts_at[i].begin(), starts_at[i].end());
std::sort(ends_at[i].begin(), ends_at[i].end(), std::greater<std::pair<int, int>>());
}
max_tree::init(1, 1, n);
min_tree::init(1, 1, n);
std::vector<bool> vis(k + 1);
std::vector<int> kol(k + 1);
std::set<int> do_kol;
for (int i = 0; i < k; i++) {
do_kol.insert(i);
}
while (!do_kol.empty()) {
std::queue<int> q;
int start = *do_kol.begin();
q.push(start);
auto rem = [&](int vv, int z) {
kol[vv] = z;
do_kol.erase(vv);
vis[vv] = 1;
refresh_start(ziomy[vv].l, n, vis);
refresh_end(ziomy[vv].r, n, vis);
};
rem(start, 0);
while (!q.empty()) {
int u = q.front();
q.pop();
std::pair<int, int> p;
while ((p = max_tree::query(1, 1, n, ziomy[u].l + 1, ziomy[u].r - 1)).first > ziomy[u].r) {
int v = p.second;
q.push(v);
rem(v, 1 - kol[u]);
}
while ((p = min_tree::query(1, 1, n, ziomy[u].l + 1, ziomy[u].r - 1)).first < ziomy[u].l) {
int v = p.second;
q.push(v);
rem(v, 1 - kol[u]);
}
}
}
bool isGood = 1;
std::vector<int> gr_s, gr_n;
gr_s.reserve(k);
gr_n.reserve(k);
for (int i = 0; i < k; i++) {
if (kol[i] == 0) {
gr_s.push_back(i);
} else {
gr_n.push_back(i);
}
}
auto check = [](const std::vector<int>& g_const) -> bool {
std::vector<int> g = g_const;
std::sort(g.begin(), g.end(), [](int a, int b) {
if (ziomy[a].l != ziomy[b].l) {
return ziomy[a].l < ziomy[b].l;
}
return ziomy[a].r > ziomy[b].r;
});
std::vector<int> st;
for (int id : g) {
int l = ziomy[id].l;
int r = ziomy[id].r;
while (!st.empty() && st.back() <= l) {
st.pop_back();
}
if (!st.empty() && st.back() < r) {
return false;
}
st.push_back(r);
}
return true;
};
isGood &= check(gr_n) & check(gr_s);
if (!isGood) {
std::cout << "NIE\n";
return;
}
for (int i = 0; i < k; i++) {
if (kol[i] == 0) {
std::cout << "S\n";
} else {
std::cout << "N\n";
}
}
}
int32_t main() {
#ifndef GARY_DBG
std::ios_base::sync_with_stdio(0);
std::cin.tie(0);
std::cout.tie(0);
#endif
int t = 1;
// std::cin >> t;
for (; t > 0; t--) {
solve();
}
return 0;
}