using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

using CHY72;

namespace CHY72{
    
    public class PointXY<T>where T:IComparable{
        public T X , Y;
        public bool Flag = false;
        public PointXY(T _X,T _Y) {
            X = _X; Y = _Y;
        }
        public static bool operator ==(PointXY<T> P1, PointXY<T> P2) {
            return (P1.X.CompareTo( P2.X) == 0 && P1.Y.CompareTo (P2.Y) == 0);
        }
        public static bool operator !=(PointXY<T> P1, PointXY<T> P2) {return !(P1 ==P2);}
        public override int GetHashCode() {return X.GetHashCode() ^ Y.GetHashCode();}
        public override bool Equals(object obj) {
            if (obj == null || this.GetType() != obj.GetType()) {return false;}
            return (this == (PointXY<T>)obj);
        }         

    }
    
}    

public class Program {
    static bool ReadLine_1(ref int num1, bool Fin0 = true) {
        string str = Console.ReadLine();
        num1 = int.Parse(str);
        return (Fin0 && num1 == 0);
    }
    static int  ReadLine_1() {
        return  int.Parse(Console.ReadLine());
    }
    static bool ReadLine_2(ref int num1, ref int num2, char Spliter = ' ', bool Fin0 = true) {
        string str = Console.ReadLine();
        num1 = int.Parse(str.Split(Spliter)[0]);
        num2 = int.Parse(str.Split(Spliter)[1]);
        return (Fin0 && num1 == 0);
    }
    static int[] ReadLine72(char Spliter = ' ') {
        return Console.ReadLine().Split(Spliter).Select(s => int.Parse(s)).ToArray();
    }

    const int DefaultMax = 727272;

    static void Main(string[] args) {
        while (true) {
            int BlockNum = ReadLine_1();
            if (BlockNum == 0) return;
            PointXY<int>[] BlockPos = new PointXY<int>[BlockNum];
            BlockPos[0] = new PointXY<int>(0,0);
            for (int i = 1; i<BlockNum ; i++) {
                int n = 0, d = 0;
                ReadLine_2(ref n, ref d);
                switch (d) {
                    case 0:
                        BlockPos[i] = new PointXY<int>(BlockPos[n].X -1,BlockPos[n].Y );
                        break;
                    case 1:
                        BlockPos[i] = new PointXY<int>(BlockPos[n].X , BlockPos[n].Y-1);
                        break;
                    case 2:
                        BlockPos[i] = new PointXY<int>(BlockPos[n].X + 1, BlockPos[n].Y);
                        break;
                    case 3:
                        BlockPos[i] = new PointXY<int>(BlockPos[n].X , BlockPos[n].Y+1);
                        break;
                }
            }
            var MaxPos = new PointXY<int>(0,0);
            var MinPos = new PointXY<int>(0,0);
            for (int i = 0; i < BlockNum; i++) {
                if (MaxPos.X < BlockPos[i].X) MaxPos.X = BlockPos[i].X;
                if (MaxPos.Y < BlockPos[i].Y) MaxPos.Y = BlockPos[i].Y;
                if (MinPos.X > BlockPos[i].X) MinPos.X = BlockPos[i].X;
                if (MinPos.Y > BlockPos[i].Y) MinPos.Y = BlockPos[i].Y;
            }
            Console.WriteLine((MaxPos.X -MinPos.X +1)+" "+(1+MaxPos.Y -MinPos .Y ));
            
        }

    }
}

Measured memory_bytes: 5876