#include #define EPS 1e-9 #define INF 1070000000LL #define MOD 1000000007LL #define fir first #define foreach(it,X) for(auto it=(X).begin();it!=(X).end();it++) #define numa(x,a) for(auto x: a) #define ite iterator #define mp make_pair #define rep(i,n) rep2(i,0,n) #define rep2(i,m,n) for(int i=m;i<(n);i++) #define pb push_back #define pf push_front #define sec second #define sz(x) ((int)(x).size()) #define ALL( c ) (c).begin(), (c).end() #define gcd(a,b) __gcd(a,b) #define mem(x,n) memset(x,n,sizeof(x)) #define endl "\n" using namespace std; template void deploy(std::ostream &os, const TUPLE &tuple){} template void deploy(std::ostream &os, const TUPLE &t){ os << (POS == 0 ? "" : ", ") << get(t); deploy(os, t); } template std::ostream& operator<<(std::ostream &os, std::pair &p){ os << "(" << p.first <<", " << p.second <<")";return os; } template std::ostream& operator<<(std::ostream &os, std::vector &v){ int remain = v.size(); os << "{"; for(auto e: v) os << e << (--remain == 0 ? "}" : ", "); return os; } template std::ostream& operator<<(std::ostream &os, std::set &v){ int remain = v.size(); os << "{"; for(auto e: v) os << e << (--remain == 0 ? "}" : ", "); return os; } template std::ostream& operator<<(std::ostream &os, std::map &mp){ int remain = mp.size(); os << "{"; for(auto e: mp) os << "(" << e.first << " -> " << e.second << ")" << (--remain == 0 ? "}" : ", "); return os; } #define DEBUG1(var0) { std::cerr << (#var0) << "=" << (var0) << endl; } #define DEBUG2(var0, var1) { std::cerr << (#var0) << "=" << (var0) << ", ";DEBUG1(var1); } #define DEBUG3(var0, var1, var2) { std::cerr << (#var0) << "=" << (var0) << ", ";DEBUG2(var1,var2); } #define DEBUG4(var0, var1, var2, var3) { std::cerr << (#var0) << "=" << (var0) << ", ";DEBUG3(var1,var2,var3); } //using ll = long long; typedef long long ll; struct Node{ int cnt; Node(){ cnt = 0; } Node(int x){ cnt = x; } }; struct Node2{ bool flag; int add; Node2(){ flag = false; add = 0; } Node2(int add_, bool flag_) { add = add_; flag = flag_; } }; template class LazySEGTree{ vector seg_tree; vector lazy; int n; inline void already(Node2 &node2) { node2.add = 0; node2.flag = false; } inline bool notyet(Node2 &node2) { return node2.flag; } inline void lazyset(Node2 &node2, Node &node){ node2.flag = true; /*埋める*/ node2.add = node.cnt; } inline Node comp(Node &n1, Node &n2) { Node n3(n1.cnt + n2.cnt); return n3; } inline Node MAXNODE(){ Node n3(0); return n3; } public: LazySEGTree(){ seg_tree.resize(NV * 2, Node()); lazy.resize(NV * 2, Node2()); } void init(int n_) { n = 1; while (n < n_) { n *= 2; } } inline void update(int a, int b, Node &v, int k, int l, int r) {//[a,b)の区間をupdate if (l >= r) { return; } if (a <= l && r <= b) { if (v.cnt == 0) { seg_tree[k].cnt = 0; }else{ seg_tree[k].cnt = r - l; } lazyset(lazy[k], v); }else if (l < b && a < r){ if (notyet(lazy[k])) {//伝播させてない /*埋める*/ int cnt_half = 0; if (lazy[k].add == 1) { cnt_half = (r - l) / 2; } seg_tree[k * 2 + 1] = seg_tree[k * 2 + 2] = Node(cnt_half); lazy[k * 2 + 1] = lazy[k * 2 + 2] = Node2(lazy[k].add, true); already(lazy[k]); } update(a, b, v, k * 2 + 1, l, (l + r) / 2); update(a, b, v, k * 2 + 2, (l + r) / 2, r); seg_tree[k] = comp(seg_tree[k * 2 + 1], seg_tree[k * 2 + 2]); } } inline void update(int a, int b, Node &v) { update(a, b, v, 0, 0, n); } inline Node query(int a, int b, int k, int l, int r) { if (r <= a || b <= l) { return MAXNODE(); } if (a <= l && r <= b) { return seg_tree[k]; } a=max(a,l); b=min(b,r); if (notyet(lazy[k])) {//伝播させてない return lazy[k].add * (b - a); } Node vl = query(a, b, k * 2 + 1, l, (l + r) / 2); Node vr = query(a, b, k * 2 + 2, (l + r) / 2, r); return comp(vl, vr); } inline Node query(int a, int b) { return query(a, b, 0, 0, n); } }; int N,Q; LazySEGTree<1 << 18> lst[2]; int main() { cin.tie(0); ios_base::sync_with_stdio(0); cin >> N >> Q; lst[0].init(N + 10); lst[1].init(N + 10); ll ansA = 0, ansB = 0; while(Q--){ int x,l,r; cin >> x >> l >> r; if (x == 0) { Node a = lst[0].query(l, r + 1); Node b = lst[1].query(l, r + 1); if (a.cnt > b.cnt) { ansA += a.cnt; } if (a.cnt < b.cnt) { ansB += b.cnt; } }else{ x--; int mycolor = x; int enemycolor = 1 - x; Node zero = Node(0); Node one = Node(1); lst[mycolor].update(l, r + 1, one); lst[enemycolor].update(l, r + 1, zero); } } ansA += (lst[0].query(0, N)).cnt; ansB += (lst[1].query(0, N)).cnt; cout << ansA << " " << ansB << endl; return 0; }