#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define mod 30013
struct Treap{
int idx = 0;
ll value = 0;
ll priority;
ll sum_over_childerns = 0;
Treap *left = nullptr, *right = nullptr;
Treap(){
priority = rand();
}
Treap(int i, ll v){
priority = rand();
idx = i;
value = (sum_over_childerns = v);
}
Treap* join(Treap* l, Treap* r){
left = l;
right = r;
sum_over_childerns = value % mod;
if(l != nullptr) {sum_over_childerns += l->sum_over_childerns;}
sum_over_childerns %= mod;
if(r != nullptr) {sum_over_childerns += r->sum_over_childerns;}
sum_over_childerns %= mod;
return this;
}
};
pair<Treap*, Treap*> split(Treap* t, ll threshold){
if(t == nullptr) return {nullptr, nullptr};
if(threshold > t->idx){
auto[l, r] = split(t->right, threshold);
return {t->join(t->left, l), r};
}else{
auto[l, r] = split(t->left, threshold);
return {l, t->join(r, t->right)};
}
}
Treap* merge(Treap* a, Treap* b){
if(a == nullptr) return b;
if(b == nullptr) return a;
if(a->priority > b->priority){
return a->join(a->left, merge(a->right, b));
}else{
return b->join(merge(a, b->left), b->right);
}
}
Treap* treap_pool;
int amount_left = 0;
Treap* t_gen(){
if(amount_left == 0){
treap_pool = new Treap[150000];
amount_left = 150000;
}
amount_left--;
return treap_pool++;
}
Treap* insert(Treap *& t, int idx, ll value){
Treap *i = t_gen();
*i =Treap(idx,value);
if(t == nullptr) return t=i;
auto[l, r] = split(t, idx); // forse idx-1?
return t=merge(l, merge(i,r));
}
int queryTreap(Treap*& t, int q){
if(t == nullptr) return 0;
auto[l,r] = split(t, q);
int s = 0;
if(r != nullptr) s+= r->sum_over_childerns;
t = merge(l,r);
return s%mod;
}
struct segTree{
vector<int> values;
int s = 0;
void u(int n, int l, int r, int i, int x){
if(i < l || r <= i){return;}
if(r-l==1){
values[n] = x;
return;
}
int m = (l+r)/2;
u(2*n, l, m, i, x); u(2*n+1, m, r, i, x);
values[n] = max(values[2*n], values[2*n+1]);
}
int q(int n, int l, int r, int ql, int qr){
if(ql <= l && r <= qr){return values[n];}
if(r <= ql || qr <= l){return 0;}
int m = (l+r)/2;
return max(q(2*n, l, m, ql, qr), q(2*n+1, m, r, ql, qr));
}
void update(int i, int x){
u(1, 0, s, i, x);
}
int query(int l, int r){
return q(1, 0, s, l, r);
}
segTree(int n){
s = 1;
while(s < n) s <<= 1;
values.resize(4*s);
fill(values.begin(), values.end(), 0);
}
};
int main(){
int N;
cin >> N;
vector<array<ll, 4>> trapezoids(N);
// INPUT AND CHANGE OF VAR
{set<ll> trapezoids_var_change;
for(int i = 0; i < N; i++){
ll a, b, c, d; cin >> a >> b >> c >> d;
trapezoids[i] = {a,b,c,d};
trapezoids_var_change.insert(a);
trapezoids_var_change.insert(b);
trapezoids_var_change.insert(c);
trapezoids_var_change.insert(d);
}
map<ll,int> idx_changer;
for(auto a = trapezoids_var_change.begin(); a != trapezoids_var_change.end(); a++){
idx_changer[*a] = idx_changer.size();
}
for(int i = 0; i < N; i++){
auto[a,b,c,d] = trapezoids[i];
trapezoids[i] = {idx_changer[a],idx_changer[b],idx_changer[c],idx_changer[d]};
}}
sort(trapezoids.begin(), trapezoids.end());
vector<int> QID(trapezoids.size());
for(int i = 0; i < QID.size(); i++){QID[i] = i;}
sort(QID.begin(), QID.end(), [&trapezoids](int a, int b){return trapezoids[a][1]<trapezoids[b][1];});
segTree seg(4*N+1);
vector<int> para_seg(N, 0);
vector<Treap*> startes_for_amount(N+1);
for(int i = 0; i <= N; i++) startes_for_amount[i] = nullptr;
vector<ll> number_of_solutions_of_i(N, 0);
int insert_id = N-1;
int query_id = N-1;
while(insert_id >= 0 || query_id >= 0){
// if after inserting insert_id i can still query query_id then i'll insert; otherwise query
if(insert_id== -1 || query_id == -1 || (insert_id != -1 && (trapezoids[insert_id][0] >= trapezoids[QID[query_id]][1]))){
// INSERT
seg.update(trapezoids[insert_id][2], max(1,para_seg[insert_id]));
insert(startes_for_amount[para_seg[insert_id]], trapezoids[insert_id][2], number_of_solutions_of_i[insert_id]);
insert_id--;
}else{
// QUERY
para_seg[QID[query_id]] = seg.query(trapezoids[QID[query_id]][3]+1, 4*N+1) + 1;
number_of_solutions_of_i[QID[query_id]] = max(1,queryTreap(startes_for_amount[para_seg[QID[query_id]]-1],trapezoids[QID[query_id]][3]+1)); // somma dei modi con tutti gli starter successivi
query_id--;
}
}
int sol = seg.query(0, 4*N+1);
cout << sol << " " << startes_for_amount[sol]->sum_over_childerns;
return 0;
}