// Arup Guha
// 3/11/2013
// Solution to COP 3503 Program #4: Skyline

import java.util.*;

public class skyline {

	public static void main(String[] args) {

		Scanner stdin = new Scanner(System.in);
		int n = stdin.nextInt();

		// Go through each case.		
		while (n != 0) {
		
			int[][] buildings = new int[n][3];

			// Read in these buildings.
			for (int i=0; i<n; i++) 
				for (int j=0; j<3; j++)
					buildings[i][j] = stdin.nextInt();
				
			// Solve and output.
			int[] sequence = getOneList(buildings);
			ArrayList<Integer> answer = condense(sequence);
			printSequence(answer);
		
			n = stdin.nextInt();
		}
	}

	// Prints the sequence a, adding a 0 at the end.
	public static void printSequence(ArrayList<Integer> a) {
		for (int i=0; i<a.size(); i++)
			System.out.print(a.get(i)+" ");
		System.out.println("0");
	}

	// Wrapper function to solve the problem.
	public static int[] getOneList(int[][] list) {
		return mergeSort(list, 0, list.length-1);
	}

	// Recursive solution to the problem, solving for list[start...end].
	public static int[] mergeSort(int[][] list,int start, int end) {

		// Base case.
		if (start == end)
			return list[start];

		int mid = (start+end)/2;
		int[] list1 = mergeSort(list, start, mid);
		int[] list2 = mergeSort(list, mid+1, end);
		return merge(list1, list2);
	}

	// Given two skylines, list1 and list2, this returns a merged skyline, that might
	// have redundant segments (2, 6, 3, 6, 5) for example.
	public static int[] merge(int[] list1, int[] list2) {

		// Make a list of all unique boundaries.
		HashSet<Integer> boundaries = new HashSet<Integer>();
		for (int i=0; i<list1.length; i+=2)
			if (!boundaries.contains(list1[i]))
				boundaries.add(list1[i]);
		for (int i=0; i<list2.length; i+=2)
			if (!boundaries.contains(list2[i]))
				boundaries.add(list2[i]);

		Iterator<Integer> temp = boundaries.iterator();

		// Sort these boundaries.
		ArrayList<Integer> vals = new ArrayList<Integer>();
		while (temp.hasNext())
			vals.add(temp.next());
		Collections.sort(vals);

		// We'll store the answer here.
		int[] ans = new int[2*vals.size()-1];
		for (int i=0; i<ans.length; i+=2)
			ans[i] = vals.get(i/2);

		// Fill in each slot of the answer, one by one.
		int oneIndex = -1, twoIndex = -1;
		for (int i=1; i<ans.length; i+=2) {
			
			// Figure out what to advance.
			if (oneIndex+1<list1.length && list1[oneIndex+1] <= ans[i-1]) oneIndex += 2;
			if (twoIndex+1<list2.length && list2[twoIndex+1] <= ans[i-1]) twoIndex += 2;

			// Obtain the current heights of each skyline.
			int oneVal = 0, twoVal = 0;
			if (oneIndex > 0 && oneIndex < list1.length) oneVal = list1[oneIndex];
			if (twoIndex > 0 && twoIndex < list2.length) twoVal = list2[twoIndex];

			ans[i] = Math.max(oneVal, twoVal);
		}

		return ans;
	}
	
	// Condenses the skyline sequence so that no two consecutive segments have the same height.
	public static ArrayList<Integer> condense(int[] sequence) {
		
		ArrayList<Integer> list = new ArrayList<Integer>();
		list.add(sequence[0]);
		
		// Go through each boundary.
		int i = 1, j = 1;
		while (i<sequence.length) {
			
			// Advance through equal-sized buildings.
			while (i+2 < sequence.length && sequence[i] == sequence[i+2]) i+=2;
			
			// These are the two numbers we need to add.
			list.add(sequence[i]);
			list.add(sequence[i+1]);
			i += 2;
		}
		
		return list;
	}
}

