// Arup Guha
// 12/25/2017
// Solution to 2017 NCPC Problem C: Compass Card Sales

import java.util.*;
import java.io.*;

public class c {

	public static int n;
	public static card[] cards;
	public static entry[][] colors;

	public static void main(String[] args) throws Exception {

		BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
		n = Integer.parseInt(stdin.readLine().trim());
		cards = new card[n];

		// Read cards.
		for (int i=0; i<n; i++) {
			StringTokenizer tok = new StringTokenizer(stdin.readLine());
			int r = Integer.parseInt(tok.nextToken());
			int g = Integer.parseInt(tok.nextToken());
			int b = Integer.parseInt(tok.nextToken());
			int myid = Integer.parseInt(tok.nextToken());
			cards[i] = new card(r,g,b,myid);
		}

		// Set up three arrays of entries.
		colors = new entry[3][360];
		for (int i=0; i<3; i++)
			for (int j=0; j<360; j++)
				colors[i][j] = new entry();

		for (int i=0; i<3; i++)
			for (int j=0; j<n; j++)
				colors[i][cards[j].dark[i]].add(cards[j]);

		// Update L, R.
		for (int i=0; i<3; i++)
			setupLR(colors[i]);

		// Set up the differences for all cards.
		for (int i=0; i<n; i++) {
			cards[i].diff = 0;
			for (int j=0; j<3; j++)
				cards[i].diff += colors[j][cards[i].dark[j]].left + colors[j][cards[i].dark[j]].right;
		}

		// This is our tree set of cards.
		TreeSet<card> myt = new TreeSet<card>();
		for (int  i=0; i<n; i++)
			myt.add(cards[i]);

		StringBuffer sb = new StringBuffer();
		for (int i=0; i<n; i++) {

			// Our next card to get rid of.
			card cur = myt.pollFirst();
			sb.append(cur.ID+"\n");

			// Recalculate left and right values...
			if(i <n-1) recalc(colors, cur, myt);
		}

		System.out.print(sb);
	}

	// Recalculate necessary left, right values and update TreeSet as necessary.
	public static void recalc(entry[][] colors, card c, TreeSet<card> myt) {

		// Remove this card from each color treeset.
		for (int i=0; i<3; i++) colors[i][c.dark[i]].list.remove(c);

		// Do L/R changes for each color
		for (int i=0; i<3; i++) {

			// Left and Right of key changes.
			if (colors[i][c.dark[i]].list.size() == 1) setupLR(colors[i], c.dark[i]);

			// We are gone, must look left and right and reset these.
			else if (colors[i][c.dark[i]].list.size() == 0) {

				int lKey = colors[i][c.dark[i]].leftI;
				if (colors[i][lKey].list.size() == 1) setupLR(colors[i], lKey);

				int rKey = colors[i][c.dark[i]].rightI;
				if (colors[i][rKey].list.size() == 1) setupLR(colors[i], rKey);
			}
		}

		// Now, take the appropriate cards out of the appropriate tree sets.
		for (int i=0; i<3; i++) {

			// Left and Right of key changes.
			if (colors[i][c.dark[i]].list.size() == 1) {
				card tmp = colors[i][c.dark[i]].list.pollFirst();
				myt.remove(tmp);
				tmp.diff = 0;
				for (int j=0; j<3; j++)
					tmp.diff += colors[j][tmp.dark[j]].left + colors[j][tmp.dark[j]].right;
				myt.add(tmp);
				colors[i][tmp.dark[i]].add(tmp);
			}

			// We are gone, must look left and right and reset these.
			else if (colors[i][c.dark[i]].list.size() == 0) {

				int lKey = colors[i][c.dark[i]].leftI;
				if (colors[i][lKey].list.size() == 1) {
					card tmp = colors[i][lKey].list.pollFirst();
					myt.remove(tmp);
					tmp.diff = 0;
					for (int j=0; j<3; j++)
						tmp.diff += colors[j][tmp.dark[j]].left + colors[j][tmp.dark[j]].right;
					myt.add(tmp);
					colors[i][lKey].add(tmp);
				}

				int rKey = colors[i][c.dark[i]].rightI;
				if (colors[i][rKey].list.size() == 1) {
					card tmp = colors[i][rKey].list.pollFirst();
					myt.remove(tmp);
					tmp.diff = 0;
					for (int j=0; j<3; j++)
						tmp.diff += colors[j][tmp.dark[j]].left + colors[j][tmp.dark[j]].right;
					myt.add(tmp);
					colors[i][rKey].add(tmp);
				}
			}

		}
	}

	public static void setupLR(entry[] color) {
		for (int i=0; i<360; i++)
			setupLR(color, i);
	}

	// Setup up left and right nearest neighbors using brute force 360 x 360...
	public static void setupLR(entry[] color, int i) {

		// These are done.
		if (color[i].list.size() != 1) return;

		// Go right.
		int myr = (i+1)%360, d = 1;
		while (color[myr].list.size() == 0) {
			myr = (myr+1)%360;
			d++;
		}
		color[i].right = d;
		color[i].rightI = myr;

		// Go left.
		int myl = (i+359)%360;
		d = 1;
		while (color[myl].list.size() == 0) {
			myl = (myl+359)%360;
			d++;
		}
		color[i].left = d;
		color[i].leftI = myl;
	}
}

class card implements Comparable<card> {

	public int[] dark;
	public int ID;
	public int diff;

	public card(int myr, int myg, int myb, int myID) {
		dark = new int[3];
		dark[0] = myr;
		dark[1] = myg;
		dark[2] = myb;
		ID = myID;
		diff = 0;
	}

	public int compareTo(card other) {
		if (this.diff != other.diff) return this.diff - other.diff;
		return other.ID - this.ID;
	}
}

class entry {

	public TreeSet<card> list;
	public int left;
	public int right;
	public int leftI;
	public int rightI;

	public entry() {
		list = new TreeSet<card>(new MyCardComp());
		left = -1;
		right = -1;
		leftI = 0;
		rightI = 0;
	}

	public void add(card c) {
		list.add(c);
		if (list.size() > 1) {
			left = 0;
			right = 0;
		}
	}

	public void remove(card c) {
		list.remove(c);
	}
}

class MyCardComp implements Comparator<card>{

    public int compare(card c1, card c2) {
        return c2.ID - c1.ID;
    }
}