import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashSet;
import java.util.StringTokenizer;
import java.util.TreeSet;

public class E {
	static PrintWriter out = new PrintWriter(System.out);
	static int M;
	static int maxN = 200001;
	static int curN;
	static ArrayList<Edge> adj[];
	static ArrayList<VecL[]> candidates;
	static int[] sz;
	static final boolean debug = false;
	public static void main(String[] args) {
		FS in = new FS();
		int N = in.nextInt();
		M = in.nextInt();

		ArrayDeque<Edge> es[] = new ArrayDeque[N];
		for(int i = 0; i < N; i++) es[i] = new ArrayDeque<Edge>();
		for(int i = 0; i < N-1; i++) {
			int u = in.nextInt()-1;
			int v = in.nextInt()-1;
			long m = in.nextLong();
			long b = in.nextLong();
			Edge e = new Edge(u,v,m,b);
			es[u].add(e);
			es[v].add(e);
		}

		curN = N;
		adj = new ArrayList[maxN];
		for(int i = 0; i < maxN; i++) adj[i] = new ArrayList<Edge>();
		fixTree(0, -1, es);

		if(debug) {
			System.out.println("N= "+ curN);
			for(int i = 0; i < curN; i++) {
				System.out.println(i+" "+adj[i].toString());
			}
		}

		candidates = new ArrayList<>();
		sz = new int[curN];
		solve(0);

		CHT cht = new CHT(1);
		for(VecL[] cs : candidates) {
			for(VecL v : cs) {
				cht.add(v.x, v.y);
			}
		}

		for(int i = 0; i < M; i++) out.print(cht.query(i)+" ");
		out.println();
		out.close();
	}

	static void solve(int node) {
		szdfs(node, -1);
		if(sz[node] == 1) return; // base case, no edges
		Edge e = getEdgetroid(node, -1, sz[node], null);
		e.blocked = true;

		//solve on this guy
		ArrayList<VecL> left = new ArrayList<VecL>();
		ArrayList<VecL> right = new ArrayList<VecL>();
		makeLines(e.u, -1, e.m, e.b, left);
		makeLines(e.v, -1, 0, 0, right);

		VecL[] minskowski = minkowskiSum(getHull(removeDupes(left)), getHull(removeDupes(right)));
		candidates.add(minskowski);

		if(debug) {
			System.out.println("Decomp on: "+e);
			System.out.println("  Left: "+left.toString());
			System.out.println("  Right: "+right.toString());
			System.out.println("  Minskowski: "+Arrays.toString(minskowski));
		}

		//now solve on the remaining stuff
		solve(e.u);
		solve(e.v);
	}

	static void makeLines(int node, int p, long curM, long curB, ArrayList<VecL> vecs) {
		int to = 0;
		for(Edge e : adj[node]) {
			if(e.blocked || e.to(node) == p) continue;
			to++;
			makeLines(e.to(node), node, curM + e.m, curB + e.b, vecs);
		}
		if(to == 0) vecs.add(new VecL(curM, curB));
	}

	static Edge getEdgetroid(int node, int p, int totalSz, Edge curBest) {
		Edge myBest = null;
		for(Edge e : adj[node]) {
			if(e.blocked || e.to(node) == p) continue;
			if(myBest == null || myBest.getDif(totalSz) > e.getDif(totalSz)) {
				myBest = e;
			}
		}
		if(curBest != null && (myBest == null || curBest.getDif(totalSz) <= myBest.getDif(totalSz))) return curBest;
		return getEdgetroid(myBest.to(node), node, totalSz, myBest);
	}
	static void szdfs(int node, int p) {
		sz[node] = 1;
		for(Edge e : adj[node]) {
			if(e.blocked || e.to(node) == p) continue;
			szdfs(e.to(node), node);
			sz[node] += sz[e.to(node)];
		}
	}

	static void fixTree(int node, int p, ArrayDeque<Edge> es[]) {
		int cur = node;
		while(!es[node].isEmpty()) {
			if(es[node].size() <= 2) {
				while(!es[node].isEmpty()) {
					Edge e = es[node].poll();
					e.swap(node, cur);
					adj[cur].add(e);
					adj[e.to(cur)].add(e);
					es[e.to(cur)].remove(e);
					fixTree(e.to(cur), cur, es);
				}
			}
			else {
				//add left edge to my current guy
				Edge e = es[node].poll();
				e.swap(node, cur);
				adj[cur].add(e);
				adj[e.to(cur)].add(e);
				es[e.to(cur)].remove(e);
				fixTree(e.to(cur), cur, es);

				int next = curN++;
				Edge filler = new Edge(cur, next, 0, 0);
				adj[cur].add(filler);
				adj[next].add(filler);
				cur = next;
			}
		}
	}

	static class Edge{
		int u,v;
		long m,b;
		boolean blocked;
		public Edge(int uu, int vv, long mm, long bb) {
			u=uu; v=vv; m=mm; b=bb;
			blocked = false;
		}
		int to(int node) { return u^v^node; }
		void swap(int from, int to) {
			if(u == from) u = to;
			else if(v == from) v = to;
			else throw null;
		}
		int getDif(int totalSz) {
			int s1 = Math.min(sz[u], sz[v]);
			int s2 = totalSz - Math.min(sz[u], sz[v]);
			return Math.abs(s1-s2);
		}
		@Override
		public String toString() {
			return "[u="+u+" v="+v+" m="+m+" b="+b+"]";
		}
	}

	// Computes the convex hull of the Minkowski sum of 2 convex polygons.
	// Polygons must be in CCW order and returns the sum in same order
	// O(N + M) where N and M are the sizes of the two polygons
	public static VecL[] minkowskiSum(VecL[] c1, VecL[] c2) {
		int n = c1.length, m = c2.length;
		if(n == 1) return simple(c1, c2);
		if(m == 1) return simple(c2, c1);
		VecL[] hull = new VecL[n+m];
		SegL[] s1 = toSeg(c1);
		SegL[] s2 = toSeg(c2);
		int nst = getSt(s1), mst = getSt(s2);
		int rId = 0, ni = nst, mi = mst;
		while(rId < n+m) {
			SegL seg, seg2 = null;
			if(better(ni,mi,s1,s2)) {
				seg = s1[ni]; if(rId == 0) seg2 = s2[mi];
				ni = (ni+1)%n;
				if(ni == nst) ni = -1;
			}
			else {
				seg = s2[mi]; if(rId == 0) seg2 = s1[ni];
				mi = (mi+1)%m;
				if(mi == mst) mi = -1;
			}
			if(rId == 0) hull[rId++] = seg.from.add(seg2.from);
			hull[rId] = hull[rId-1].add(seg.dir);
			rId++;
		}
		VecL[] res = new VecL[n+m];
		int cId = 0;
		for(int i = 0; i < hull.length; i++) {
			if(valid(hull[(i-1+hull.length)%hull.length], hull[i], hull[(i+1)%hull.length])) res[cId++] = hull[i];
		}

		return Arrays.copyOf(res, cId);
	}

	static boolean valid(VecL a, VecL b, VecL c) {
		VecL d1 = b.sub(a), d2 = c.sub(b);
		long cross = d1.cross(d2), dot = d1.dot(d2);
		return cross != 0 || (cross == 0 && dot < 0);
	}

	static VecL[] simple(VecL[] pnt, VecL[] c) {
		VecL[] res = new VecL[c.length];
		for(int i = 0; i < c.length; i++) res[i] = c[i].add(pnt[0]);
		return res;
	}

	static SegL[] toSeg(VecL pnts[]) {
		SegL[] res = new SegL[pnts.length];
		for(int i = 0; i < pnts.length; i++) {
			res[i] = new SegL(pnts[i], pnts[(i+1)%pnts.length]);
		}
		return res;
	}

	static boolean better(int i1, int i2, SegL c1[], SegL c2[]) {
		if(i1 == -1) return false;
		if(i2 == -1) return true;
		return c1[i1].dir.radialCompare(c2[i2].dir) <= 0;
	}

	static int getSt(SegL[] segs) {
		if(segs.length == 1) return -1;
		if(segs.length == 2) {
			if(segs[0].dir.y > 0 || (segs[0].dir.y == 0 && segs[0].dir.x > 0)) return 0;
			return 1;
		}
		for(int i = 0; i < segs.length; i++) {
			SegL prev = i == 0 ? segs[segs.length-1] : segs[i-1];
			SegL cur = segs[i];
			if(cur.dir.y >= 0 && prev.dir.y < 0) return i;
		}
		return -1;
	}

	public static VecL[] removeDupes(ArrayList<VecL> points) {
		HashSet<VecL> set=new HashSet<>();
		for (VecL v:points)
			set.add(v);
		int counter=0;
		VecL res[] = new VecL[set.size()];
		for (VecL v:set) res[counter++]=v;
		return res;
	}
	// returns the hull in CCW order
	public static VecL[] getHull(VecL[] points) {
		points=points.clone();
		Arrays.sort(points);
		if (points.length<3)
			return points;
		int n=points.length, j=2, k=2;
		VecL[] lo=new VecL[n], up=new VecL[n];
		lo[0]=points[0];
		lo[1]=points[1];
		for (int i=2; i<n; i++) {
			VecL p=points[i];
			while (j>1&&!right(lo[j-2], lo[j-1], p)) j--;
			lo[j++]=p;
		}
		up[0]=points[n-1];
		up[1]=points[n-2];
		for (int i=n-3; i>=0; i--) {
			VecL p=points[i];
			while (k>1&&!right(up[k-2], up[k-1], p)) k--;
			up[k++]=p;
		}

		VecL[] res=new VecL[j+k-2];
		for (int i=0; i<k; i++) res[i]=up[i];
		for (int i=1; i<j-1; i++) res[k+i-1]=lo[i];
		return res;
	}

	// check if a->b->c are in the right order
	static boolean right(VecL a, VecL b, VecL c) {
		return b.sub(a).cross(c.sub(a))>0;
	}

	static class VecL implements Comparable<VecL>{
		long x,y;
		public VecL(long xx, long yy) {
			x=xx;
			y=yy;
		}
		public VecL add(VecL o) { return new VecL(x+o.x, y+o.y);}
		public VecL sub(VecL o) { return new VecL(x-o.x, y-o.y);}
		public long cross(VecL o) { return x*o.y - y*o.x;}
		public long dot(VecL o) { return x*o.x + y*o.y;}
		public int quadrant() {
			if (x==0||y==0)
				if (y==0)
					if (x>=0)
						return 1;
					else
						return 3;
				else
					if (y>=0)
						return 2;
					else
						return 4;
			if (x>0)
				if (y>0)
					return 1;
				else
					return 4;
			else
				if (y>0)
					return 2;
				else
					return 3;
		}

		public int radialCompare(VecL o) {
			if (quadrant()==o.quadrant())
				return -Long.signum(cross(o));
			return Integer.compare(quadrant(), o.quadrant());
		}
		@Override
		public int compareTo(VecL o) {
			if(x!=o.x) return Long.compare(x, o.x);
			return Long.compare(y, o.y);
		}
		@Override
		public String toString() {
			return "("+x+","+y+")";
		}
		public int hashCode() {
			return Long.hashCode(x<<13^(y*57));
		}

		public boolean equals(Object oo) {
			VecL o=(VecL)oo;
			return x==o.x&&y==o.y;
		}
	}

	static class SegL{
		VecL from, to, dir;
		public SegL(VecL a, VecL b) {
			from=a;
			to=b;
			dir = to.sub(from);
		}
		@Override
		public String toString() {
			return "["+from+" -> "+to+"]";
		}
	}

	static class CHT {
		TreeSet<Line> hull;
		int type;  boolean query  = false;
		Comparator<Line> comp = new Comparator<Line>() {
			public int compare(Line a, Line b) {
				if (!query) return type * Long.compare(a.m, b.m);
				if (a.left == b.left) return Long.compare(a.m, b.m);
				return Double.compare(a.left, b.left);
			}
		};
		// -1 for min; +1 for max
		public CHT(int typee) { type = typee;  hull = new TreeSet<>(comp); }

		public void add(long m, long b) { add(new Line(m, b)); }

		public void add(Line a) {
			Line[] LR = { hull.lower(a), hull.ceiling(a) };
			for (int i = 0; i < 2; i++)
				if (LR[i] != null && LR[i].m == a.m) {
					if (type == 1 && LR[i].b >= a.b) return;
					if (type == -1 && LR[i].b <= a.b) return;
					remove(LR[i]);
				}
			hull.add(a);
			Line L = hull.lower(a), R = hull.higher(a);
			if (L != null && R != null && a.inter(R) <= R.left) {
				hull.remove(a);
				return;
			}
			Line LL = (L != null) ? hull.lower(L) : null;
			Line RR = (R != null) ? hull.higher(R) : null;
			if (L != null) a.left = a.inter(L);
			if (R != null) R.left = a.inter(R);
			while (LL != null && L.left >= a.inter(LL)) {
				remove(L);
				a.left = a.inter(L = LL);
				LL = hull.lower(L);
			}
			while (RR != null && R.inter(RR) <= a.inter(RR)) {
				remove(R);
				RR.left = a.inter(R = RR);
				RR = hull.higher(R);
			}
		}

		public long query(long x) {
			Line temp = new Line(0, 0, 0);
			temp.left = x;  query = true;
			long ans = (long) hull.floor(temp).eval(x);
			query = false;  return ans;
		}

		private void remove(Line x) { hull.remove(x); }

		public int size() { return hull.size(); }

		static class Line {
			long m, b; double left = Long.MIN_VALUE;
			public Line(long mm, long x, long y) { m = mm; b = -m * x + y; }
			public Line(long mm, long bb) { m = mm; b = bb; }
			public long eval(long x) { return m * x + b; }
			public double inter(Line x) {
				return (double) (x.b - this.b) / (double) (this.m - x.m);
			}
		}
	}

	static class FS{
		BufferedReader br;
		StringTokenizer st;
		public FS() {
			br = new BufferedReader(new InputStreamReader(System.in));
		}
		String next() {
			while(st == null || !st.hasMoreElements()) {
				try {st = new StringTokenizer(br.readLine());}
				catch(Exception e) { throw null;}
			}
			return st.nextToken();
		}
		int nextInt() { return Integer.parseInt(next());}
		double nextDouble() { return Double.parseDouble(next());}
		long nextLong() { return Long.parseLong(next());}
		int[] NIA(int n) {
			int r[] = new int[n];
			for(int i = 0; i < n; i++) r[i] = nextInt();
			return r;
		}
		long[] NLA(int n) {
			long r[] = new long[n];
			for(int i = 0; i < n; i++) r[i] = nextLong();
			return r;
		}
		char[][] grid(int r, int c){
			char res[][] = new char[r][c];
			for(int i = 0; i < r; i++) {
				char l[] = next().toCharArray();
				for(int j = 0; j < c; j++) {
					res[i][j] = l[j];
				}
			}
			return res;
		}
	}

}


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashSet;
import java.util.StringTokenizer;
import java.util.TreeSet;

public class E4 {
	static PrintWriter out = new PrintWriter(System.out);
	static int M;
	static int maxN = 200001;
	static int curN;
	static Edge adj[][];
	static int curE[];
	static ArrayList<VecL[]> candidates;
	static int[] sz;
	static final boolean debug = false;
	public static void main(String[] args) {
		FS in = new FS();
		int N = in.nextInt();
		M = in.nextInt();

		ArrayDeque<Edge> es[] = new ArrayDeque[N];
		for(int i = 0; i < N; i++) es[i] = new ArrayDeque<Edge>();
		for(int i = 0; i < N-1; i++) {
			int u = in.nextInt()-1;
			int v = in.nextInt()-1;
			long m = in.nextLong();
			long b = in.nextLong();
			Edge e = new Edge(u,v,m,b);
			es[u].add(e);
			es[v].add(e);
		}

		curN = N;
		adj = new Edge[maxN][3];
		curE = new int[maxN];
		fixTree(0, -1, es);

		if(debug) {
			System.out.println("N= "+ curN);
			for(int i = 0; i < curN; i++) {
				System.out.println(i+" "+adj[i].toString());
			}
		}

		candidates = new ArrayList<>();
		sz = new int[curN];
		solve(0);

		CHT cht = new CHT(1);
		for(VecL[] cs : candidates) {
			for(VecL v : cs) {
				cht.add(v.x, v.y);
			}
		}

		for(int i = 0; i < M; i++) out.print(cht.query(i)+" ");
		out.println();
		out.close();
	}

	static void solve(int node) {
		szdfs(node, -1);
		if(sz[node] == 1) return; // base case, no edges
		Edge e = getEdgetroid(node, -1, sz[node], null);
		e.blocked = true;

		//solve on this guy
		ArrayList<VecL> left = new ArrayList<VecL>();
		ArrayList<VecL> right = new ArrayList<VecL>();
		makeLines(e.u, -1, e.m, e.b, left);
		makeLines(e.v, -1, 0, 0, right);

		VecL[] minskowski = minkowskiSum(getHull(removeDupes(left)), getHull(removeDupes(right)));
		candidates.add(minskowski);

		if(debug) {
			System.out.println("Decomp on: "+e);
			System.out.println("  Left: "+left.toString());
			System.out.println("  Right: "+right.toString());
			System.out.println("  Minskowski: "+Arrays.toString(minskowski));
		}

		//now solve on the remaining stuff
		solve(e.u);
		solve(e.v);
	}

	static void makeLines(int node, int p, long curM, long curB, ArrayList<VecL> vecs) {
		int to = 0;
		for(Edge e : adj[node]) {
			if(e == null || e.blocked || e.to(node) == p) continue;
			to++;
			makeLines(e.to(node), node, curM + e.m, curB + e.b, vecs);
		}
		if(to == 0) vecs.add(new VecL(curM, curB));
	}

	static Edge getEdgetroid(int node, int p, int totalSz, Edge curBest) {
		Edge myBest = null;
		for(Edge e : adj[node]) {
			if(e == null || e.blocked || e.to(node) == p) continue;
			if(myBest == null || myBest.getDif(totalSz) > e.getDif(totalSz)) {
				myBest = e;
			}
		}
		if(curBest != null && (myBest == null || curBest.getDif(totalSz) <= myBest.getDif(totalSz))) return curBest;
		return getEdgetroid(myBest.to(node), node, totalSz, myBest);
	}
	static void szdfs(int node, int p) {
		sz[node] = 1;
		for(Edge e : adj[node]) {
			if(e == null || e.blocked || e.to(node) == p) continue;
			szdfs(e.to(node), node);
			sz[node] += sz[e.to(node)];
		}
	}

	static void fixTree(int node, int p, ArrayDeque<Edge> es[]) {
		int cur = node;
		while(!es[node].isEmpty()) {
			if(es[node].size() <= 2) {
				while(!es[node].isEmpty()) {
					Edge e = es[node].poll();
					e.swap(node, cur);
					int to = e.to(cur);
					addEdge(cur, to, e, false, es);
					fixTree(to, cur, es);
				}
			}
			else {
				//add left edge to my current guy
				Edge e = es[node].poll();
				e.swap(node, cur);
				int to = e.to(cur);
				addEdge(cur, to, e, false, es);
				fixTree(to, cur, es);

				int next = curN++;
				Edge filler = new Edge(cur, next, 0, 0);
				addEdge(cur, next, filler, true, es);
				cur = next;
			}
		}
	}
	static void addEdge(int a, int b, Edge e, boolean filler, ArrayDeque<Edge> es[]) {
		adj[a][curE[a]++] = e;
		adj[b][curE[b]++] = e;
		if(!filler) es[b].remove(e);
	}

	static class Edge{
		int u,v;
		long m,b;
		boolean blocked;
		public Edge(int uu, int vv, long mm, long bb) {
			u=uu; v=vv; m=mm; b=bb;
			blocked = false;
		}
		int to(int node) { return u^v^node; }
		void swap(int from, int to) {
			if(u == from) u = to;
			else if(v == from) v = to;
			else throw null;
		}
		int getDif(int totalSz) {
			int s1 = Math.min(sz[u], sz[v]);
			int s2 = totalSz - Math.min(sz[u], sz[v]);
			return Math.abs(s1-s2);
		}
		@Override
		public String toString() {
			return "[u="+u+" v="+v+" m="+m+" b="+b+"]";
		}
	}

	// Computes the convex hull of the Minkowski sum of 2 convex polygons.
	// Polygons must be in CCW order and returns the sum in same order
	// O(N + M) where N and M are the sizes of the two polygons
	public static VecL[] minkowskiSum(VecL[] c1, VecL[] c2) {
		int n = c1.length, m = c2.length;
		if(n == 1) return simple(c1, c2);
		if(m == 1) return simple(c2, c1);
		VecL[] hull = new VecL[n+m];
		SegL[] s1 = toSeg(c1);
		SegL[] s2 = toSeg(c2);
		int nst = getSt(s1), mst = getSt(s2);
		int rId = 0, ni = nst, mi = mst;
		hull[rId++] = s1[ni].from.add(s2[mi].from);
		while(rId < n+m) {
			if(better(ni,mi,s1,s2)) {
				hull[rId++] = hull[rId-1].add(s1[ni++].dir);
				if(ni >= n) ni = 0;
				if(ni == nst) ni = -1;
			}
			else {
				hull[rId++] = hull[rId-1].add(s2[mi++].dir);
				if(mi >= m) mi = 0;
				if(mi == mst) mi = -1;
			}
		}
		VecL[] res = new VecL[n+m];
		int cId = 0;
		for(int i = 0; i < hull.length; i++) {
			if(valid(hull[(i-1+hull.length)%hull.length], hull[i], hull[(i+1)%hull.length])) res[cId++] = hull[i];
		}

		return Arrays.copyOf(res, cId);
	}

	static boolean valid(VecL a, VecL b, VecL c) {
		VecL d1 = b.sub(a), d2 = c.sub(b);
		long cross = d1.cross(d2), dot = d1.dot(d2);
		return cross != 0 || (cross == 0 && dot < 0);
	}

	static VecL[] simple(VecL[] pnt, VecL[] c) {
		VecL[] res = new VecL[c.length];
		for(int i = 0; i < c.length; i++) res[i] = c[i].add(pnt[0]);
		return res;
	}

	static SegL[] toSeg(VecL pnts[]) {
		SegL[] res = new SegL[pnts.length];
		for(int i = 0; i < pnts.length; i++) {
			res[i] = new SegL(pnts[i], pnts[(i+1)%pnts.length]);
		}
		return res;
	}

	static boolean better(int i1, int i2, SegL c1[], SegL c2[]) {
		if(i1 == -1) return false;
		if(i2 == -1) return true;
		return c1[i1].dir.radialCompare(c2[i2].dir) <= 0;
	}

	static int getSt(SegL[] segs) {
		if(segs.length == 1) return -1;
		if(segs.length == 2) {
			if(segs[0].dir.y > 0 || (segs[0].dir.y == 0 && segs[0].dir.x > 0)) return 0;
			return 1;
		}
		for(int i = 0; i < segs.length; i++) {
			SegL prev = i == 0 ? segs[segs.length-1] : segs[i-1];
			SegL cur = segs[i];
			if(cur.dir.y >= 0 && prev.dir.y < 0) return i;
		}
		return -1;
	}

	public static VecL[] removeDupes(ArrayList<VecL> points) {
		HashSet<VecL> set=new HashSet<>();
		for (VecL v:points)
			set.add(v);
		int counter=0;
		VecL res[] = new VecL[set.size()];
		for (VecL v:set) res[counter++]=v;
		return res;
	}
	// returns the hull in CCW order
	public static VecL[] getHull(VecL[] points) {
		points=points.clone();
		Arrays.sort(points);
		if (points.length<3)
			return points;
		int n=points.length, j=2, k=2;
		VecL[] lo=new VecL[n], up=new VecL[n];
		lo[0]=points[0];
		lo[1]=points[1];
		for (int i=2; i<n; i++) {
			VecL p=points[i];
			while (j>1&&!right(lo[j-2], lo[j-1], p)) j--;
			lo[j++]=p;
		}
		up[0]=points[n-1];
		up[1]=points[n-2];
		for (int i=n-3; i>=0; i--) {
			VecL p=points[i];
			while (k>1&&!right(up[k-2], up[k-1], p)) k--;
			up[k++]=p;
		}

		VecL[] res=new VecL[j+k-2];
		for (int i=0; i<k; i++) res[i]=up[i];
		for (int i=1; i<j-1; i++) res[k+i-1]=lo[i];
		return res;
	}

	// check if a->b->c are in the right order
	static boolean right(VecL a, VecL b, VecL c) {
		return b.sub(a).cross(c.sub(a))>0;
	}

	static class VecL implements Comparable<VecL>{
		long x,y;
		public VecL(long xx, long yy) {
			x=xx;
			y=yy;
		}
		public VecL add(VecL o) { return new VecL(x+o.x, y+o.y);}
		public VecL sub(VecL o) { return new VecL(x-o.x, y-o.y);}
		public long cross(VecL o) { return x*o.y - y*o.x;}
		public long dot(VecL o) { return x*o.x + y*o.y;}
		public int quadrant() {
			if (x==0||y==0)
				if (y==0)
					if (x>=0)
						return 1;
					else
						return 3;
				else
					if (y>=0)
						return 2;
					else
						return 4;
			if (x>0)
				if (y>0)
					return 1;
				else
					return 4;
			else
				if (y>0)
					return 2;
				else
					return 3;
		}

		public int radialCompare(VecL o) {
			if (quadrant()==o.quadrant())
				return -Long.signum(cross(o));
			return Integer.compare(quadrant(), o.quadrant());
		}
		@Override
		public int compareTo(VecL o) {
			if(x!=o.x) return Long.compare(x, o.x);
			return Long.compare(y, o.y);
		}
		@Override
		public String toString() {
			return "("+x+","+y+")";
		}
		public int hashCode() {
			return Long.hashCode(x<<13^(y*57));
		}

		public boolean equals(Object oo) {
			VecL o=(VecL)oo;
			return x==o.x&&y==o.y;
		}
	}

	static class SegL{
		VecL from, to, dir;
		public SegL(VecL a, VecL b) {
			from=a;
			to=b;
			dir = to.sub(from);
		}
		@Override
		public String toString() {
			return "["+from+" -> "+to+"]";
		}
	}

	static class CHT {
		TreeSet<Line> hull;
		int type;  boolean query  = false;
		Comparator<Line> comp = new Comparator<Line>() {
			public int compare(Line a, Line b) {
				if (!query) return type * Long.compare(a.m, b.m);
				if (a.left == b.left) return Long.compare(a.m, b.m);
				return Double.compare(a.left, b.left);
			}
		};
		// -1 for min; +1 for max
		public CHT(int typee) { type = typee;  hull = new TreeSet<>(comp); }

		public void add(long m, long b) { add(new Line(m, b)); }

		public void add(Line a) {
			Line[] LR = { hull.lower(a), hull.ceiling(a) };
			for (int i = 0; i < 2; i++)
				if (LR[i] != null && LR[i].m == a.m) {
					if (type == 1 && LR[i].b >= a.b) return;
					if (type == -1 && LR[i].b <= a.b) return;
					remove(LR[i]);
				}
			hull.add(a);
			Line L = hull.lower(a), R = hull.higher(a);
			if (L != null && R != null && a.inter(R) <= R.left) {
				hull.remove(a);
				return;
			}
			Line LL = (L != null) ? hull.lower(L) : null;
			Line RR = (R != null) ? hull.higher(R) : null;
			if (L != null) a.left = a.inter(L);
			if (R != null) R.left = a.inter(R);
			while (LL != null && L.left >= a.inter(LL)) {
				remove(L);
				a.left = a.inter(L = LL);
				LL = hull.lower(L);
			}
			while (RR != null && R.inter(RR) <= a.inter(RR)) {
				remove(R);
				RR.left = a.inter(R = RR);
				RR = hull.higher(R);
			}
		}

		public long query(long x) {
			if(hull.size() == 0) return 0;
			Line temp = new Line(0, 0, 0);
			temp.left = x;  query = true;
			long ans = (long) hull.floor(temp).eval(x);
			query = false;  return ans;
		}

		private void remove(Line x) { hull.remove(x); }

		public int size() { return hull.size(); }

		static class Line {
			long m, b; double left = Long.MIN_VALUE;
			public Line(long mm, long x, long y) { m = mm; b = -m * x + y; }
			public Line(long mm, long bb) { m = mm; b = bb; }
			public long eval(long x) { return m * x + b; }
			public double inter(Line x) {
				return (double) (x.b - this.b) / (double) (this.m - x.m);
			}
		}
	}

	static class FS{
		BufferedReader br;
		StringTokenizer st;
		public FS() {
			br = new BufferedReader(new InputStreamReader(System.in));
		}
		String next() {
			while(st == null || !st.hasMoreElements()) {
				try {st = new StringTokenizer(br.readLine());}
				catch(Exception e) { throw null;}
			}
			return st.nextToken();
		}
		int nextInt() { return Integer.parseInt(next());}
		double nextDouble() { return Double.parseDouble(next());}
		long nextLong() { return Long.parseLong(next());}
		int[] NIA(int n) {
			int r[] = new int[n];
			for(int i = 0; i < n; i++) r[i] = nextInt();
			return r;
		}
		long[] NLA(int n) {
			long r[] = new long[n];
			for(int i = 0; i < n; i++) r[i] = nextLong();
			return r;
		}
		char[][] grid(int r, int c){
			char res[][] = new char[r][c];
			for(int i = 0; i < r; i++) {
				char l[] = next().toCharArray();
				for(int j = 0; j < c; j++) {
					res[i][j] = l[j];
				}
			}
			return res;
		}
	}

}


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashSet;
import java.util.StringTokenizer;
import java.util.TreeSet;

public class E {
	static PrintWriter out = new PrintWriter(System.out);
	static int M;
	static int maxN = 200001;
	static int curN;
	static ArrayList<Edge> adj[];
	static ArrayList<VecL[]> candidates;
	static int[] sz;
	static final boolean debug = false;
	public static void main(String[] args) {
		FS in = new FS();
		int N = in.nextInt();
		M = in.nextInt();

		ArrayDeque<Edge> es[] = new ArrayDeque[N];
		for(int i = 0; i < N; i++) es[i] = new ArrayDeque<Edge>();
		for(int i = 0; i < N-1; i++) {
			int u = in.nextInt()-1;
			int v = in.nextInt()-1;
			long m = in.nextLong();
			long b = in.nextLong();
			Edge e = new Edge(u,v,m,b);
			es[u].add(e);
			es[v].add(e);
		}

		curN = N;
		adj = new ArrayList[maxN];
		for(int i = 0; i < maxN; i++) adj[i] = new ArrayList<Edge>();
		fixTree(0, -1, es);

		if(debug) {
			System.out.println("N= "+ curN);
			for(int i = 0; i < curN; i++) {
				System.out.println(i+" "+adj[i].toString());
			}
		}

		candidates = new ArrayList<>();
		sz = new int[curN];
		solve(0);

		CHT cht = new CHT(1);
		for(VecL[] cs : candidates) {
			for(VecL v : cs) {
				cht.add(v.x, v.y);
			}
		}

		for(int i = 0; i < M; i++) out.print(cht.query(i)+" ");
		out.println();
		out.close();
	}

	static void solve(int node) {
		szdfs(node, -1);
		if(sz[node] == 1) return; // base case, no edges
		Edge e = getEdgetroid(node, -1, sz[node], null);
		e.blocked = true;

		//solve on this guy
		ArrayList<VecL> left = new ArrayList<VecL>();
		ArrayList<VecL> right = new ArrayList<VecL>();
		makeLines(e.u, -1, e.m, e.b, left);
		makeLines(e.v, -1, 0, 0, right);

		VecL[] minskowski = minkowskiSum(getHull(removeDupes(left)), getHull(removeDupes(right)));
		candidates.add(minskowski);

		if(debug) {
			System.out.println("Decomp on: "+e);
			System.out.println("  Left: "+left.toString());
			System.out.println("  Right: "+right.toString());
			System.out.println("  Minskowski: "+Arrays.toString(minskowski));
		}

		//now solve on the remaining stuff
		solve(e.u);
		solve(e.v);
	}

	static void makeLines(int node, int p, long curM, long curB, ArrayList<VecL> vecs) {
		int to = 0;
		for(Edge e : adj[node]) {
			if(e.blocked || e.to(node) == p) continue;
			to++;
			makeLines(e.to(node), node, curM + e.m, curB + e.b, vecs);
		}
		if(to == 0) vecs.add(new VecL(curM, curB));
	}

	static Edge getEdgetroid(int node, int p, int totalSz, Edge curBest) {
		Edge myBest = null;
		for(Edge e : adj[node]) {
			if(e.blocked || e.to(node) == p) continue;
			if(myBest == null || myBest.getDif(totalSz) > e.getDif(totalSz)) {
				myBest = e;
			}
		}
		if(curBest != null && (myBest == null || curBest.getDif(totalSz) <= myBest.getDif(totalSz))) return curBest;
		return getEdgetroid(myBest.to(node), node, totalSz, myBest);
	}
	static void szdfs(int node, int p) {
		sz[node] = 1;
		for(Edge e : adj[node]) {
			if(e.blocked || e.to(node) == p) continue;
			szdfs(e.to(node), node);
			sz[node] += sz[e.to(node)];
		}
	}

	static void fixTree(int node, int p, ArrayDeque<Edge> es[]) {
		int cur = node;
		while(!es[node].isEmpty()) {
			if(es[node].size() <= 2) {
				while(!es[node].isEmpty()) {
					Edge e = es[node].poll();
					e.swap(node, cur);
					adj[cur].add(e);
					adj[e.to(cur)].add(e);
					es[e.to(cur)].remove(e);
					fixTree(e.to(cur), cur, es);
				}
			}
			else {
				//add left edge to my current guy
				Edge e = es[node].poll();
				e.swap(node, cur);
				adj[cur].add(e);
				adj[e.to(cur)].add(e);
				es[e.to(cur)].remove(e);
				fixTree(e.to(cur), cur, es);

				int next = curN++;
				Edge filler = new Edge(cur, next, 0, 0);
				adj[cur].add(filler);
				adj[next].add(filler);
				cur = next;
			}
		}
	}

	static class Edge{
		int u,v;
		long m,b;
		boolean blocked;
		public Edge(int uu, int vv, long mm, long bb) {
			u=uu; v=vv; m=mm; b=bb;
			blocked = false;
		}
		int to(int node) { return u^v^node; }
		void swap(int from, int to) {
			if(u == from) u = to;
			else if(v == from) v = to;
			else throw null;
		}
		int getDif(int totalSz) {
			int s1 = Math.min(sz[u], sz[v]);
			int s2 = totalSz - Math.min(sz[u], sz[v]);
			return Math.abs(s1-s2);
		}
		@Override
		public String toString() {
			return "[u="+u+" v="+v+" m="+m+" b="+b+"]";
		}
	}

	// Computes the convex hull of the Minkowski sum of 2 convex polygons.
	// Polygons must be in CCW order and returns the sum in same order
	// O(N + M) where N and M are the sizes of the two polygons
	public static VecL[] minkowskiSum(VecL[] c1, VecL[] c2) {
		int n = c1.length, m = c2.length;
		if(n == 1) return simple(c1, c2);
		if(m == 1) return simple(c2, c1);
		VecL[] hull = new VecL[n+m];
		SegL[] s1 = toSeg(c1);
		SegL[] s2 = toSeg(c2);
		int nst = getSt(s1), mst = getSt(s2);
		int rId = 0, ni = nst, mi = mst;
		while(rId < n+m) {
			SegL seg, seg2 = null;
			if(better(ni,mi,s1,s2)) {
				seg = s1[ni]; if(rId == 0) seg2 = s2[mi];
				ni = (ni+1)%n;
				if(ni == nst) ni = -1;
			}
			else {
				seg = s2[mi]; if(rId == 0) seg2 = s1[ni];
				mi = (mi+1)%m;
				if(mi == mst) mi = -1;
			}
			if(rId == 0) hull[rId++] = seg.from.add(seg2.from);
			hull[rId] = hull[rId-1].add(seg.dir);
			rId++;
		}
		VecL[] res = new VecL[n+m];
		int cId = 0;
		for(int i = 0; i < hull.length; i++) {
			if(valid(hull[(i-1+hull.length)%hull.length], hull[i], hull[(i+1)%hull.length])) res[cId++] = hull[i];
		}

		return Arrays.copyOf(res, cId);
	}

	static boolean valid(VecL a, VecL b, VecL c) {
		VecL d1 = b.sub(a), d2 = c.sub(b);
		long cross = d1.cross(d2), dot = d1.dot(d2);
		return cross != 0 || (cross == 0 && dot < 0);
	}

	static VecL[] simple(VecL[] pnt, VecL[] c) {
		VecL[] res = new VecL[c.length];
		for(int i = 0; i < c.length; i++) res[i] = c[i].add(pnt[0]);
		return res;
	}

	static SegL[] toSeg(VecL pnts[]) {
		SegL[] res = new SegL[pnts.length];
		for(int i = 0; i < pnts.length; i++) {
			res[i] = new SegL(pnts[i], pnts[(i+1)%pnts.length]);
		}
		return res;
	}

	static boolean better(int i1, int i2, SegL c1[], SegL c2[]) {
		if(i1 == -1) return false;
		if(i2 == -1) return true;
		return c1[i1].dir.radialCompare(c2[i2].dir) <= 0;
	}

	static int getSt(SegL[] segs) {
		if(segs.length == 1) return -1;
		if(segs.length == 2) {
			if(segs[0].dir.y > 0 || (segs[0].dir.y == 0 && segs[0].dir.x > 0)) return 0;
			return 1;
		}
		for(int i = 0; i < segs.length; i++) {
			SegL prev = i == 0 ? segs[segs.length-1] : segs[i-1];
			SegL cur = segs[i];
			if(cur.dir.y >= 0 && prev.dir.y < 0) return i;
		}
		return -1;
	}

	public static VecL[] removeDupes(ArrayList<VecL> points) {
		HashSet<VecL> set=new HashSet<>();
		for (VecL v:points)
			set.add(v);
		int counter=0;
		VecL res[] = new VecL[set.size()];
		for (VecL v:set) res[counter++]=v;
		return res;
	}
	// returns the hull in CCW order
	public static VecL[] getHull(VecL[] points) {
		points=points.clone();
		Arrays.sort(points);
		if (points.length<3)
			return points;
		int n=points.length, j=2, k=2;
		VecL[] lo=new VecL[n], up=new VecL[n];
		lo[0]=points[0];
		lo[1]=points[1];
		for (int i=2; i<n; i++) {
			VecL p=points[i];
			while (j>1&&!right(lo[j-2], lo[j-1], p)) j--;
			lo[j++]=p;
		}
		up[0]=points[n-1];
		up[1]=points[n-2];
		for (int i=n-3; i>=0; i--) {
			VecL p=points[i];
			while (k>1&&!right(up[k-2], up[k-1], p)) k--;
			up[k++]=p;
		}

		VecL[] res=new VecL[j+k-2];
		for (int i=0; i<k; i++) res[i]=up[i];
		for (int i=1; i<j-1; i++) res[k+i-1]=lo[i];
		return res;
	}

	// check if a->b->c are in the right order
	static boolean right(VecL a, VecL b, VecL c) {
		return b.sub(a).cross(c.sub(a))>0;
	}

	static class VecL implements Comparable<VecL>{
		long x,y;
		public VecL(long xx, long yy) {
			x=xx;
			y=yy;
		}
		public VecL add(VecL o) { return new VecL(x+o.x, y+o.y);}
		public VecL sub(VecL o) { return new VecL(x-o.x, y-o.y);}
		public long cross(VecL o) { return x*o.y - y*o.x;}
		public long dot(VecL o) { return x*o.x + y*o.y;}
		public int quadrant() {
			if (x==0||y==0)
				if (y==0)
					if (x>=0)
						return 1;
					else
						return 3;
				else
					if (y>=0)
						return 2;
					else
						return 4;
			if (x>0)
				if (y>0)
					return 1;
				else
					return 4;
			else
				if (y>0)
					return 2;
				else
					return 3;
		}

		public int radialCompare(VecL o) {
			if (quadrant()==o.quadrant())
				return -Long.signum(cross(o));
			return Integer.compare(quadrant(), o.quadrant());
		}
		@Override
		public int compareTo(VecL o) {
			if(x!=o.x) return Long.compare(x, o.x);
			return Long.compare(y, o.y);
		}
		@Override
		public String toString() {
			return "("+x+","+y+")";
		}
		public int hashCode() {
			return Long.hashCode(x<<13^(y*57));
		}

		public boolean equals(Object oo) {
			VecL o=(VecL)oo;
			return x==o.x&&y==o.y;
		}
	}

	static class SegL{
		VecL from, to, dir;
		public SegL(VecL a, VecL b) {
			from=a;
			to=b;
			dir = to.sub(from);
		}
		@Override
		public String toString() {
			return "["+from+" -> "+to+"]";
		}
	}

	static class CHT {
		TreeSet<Line> hull;
		int type;  boolean query  = false;
		Comparator<Line> comp = new Comparator<Line>() {
			public int compare(Line a, Line b) {
				if (!query) return type * Long.compare(a.m, b.m);
				if (a.left == b.left) return Long.compare(a.m, b.m);
				return Double.compare(a.left, b.left);
			}
		};
		// -1 for min; +1 for max
		public CHT(int typee) { type = typee;  hull = new TreeSet<>(comp); }

		public void add(long m, long b) { add(new Line(m, b)); }

		public void add(Line a) {
			Line[] LR = { hull.lower(a), hull.ceiling(a) };
			for (int i = 0; i < 2; i++)
				if (LR[i] != null && LR[i].m == a.m) {
					if (type == 1 && LR[i].b >= a.b) return;
					if (type == -1 && LR[i].b <= a.b) return;
					remove(LR[i]);
				}
			hull.add(a);
			Line L = hull.lower(a), R = hull.higher(a);
			if (L != null && R != null && a.inter(R) <= R.left) {
				hull.remove(a);
				return;
			}
			Line LL = (L != null) ? hull.lower(L) : null;
			Line RR = (R != null) ? hull.higher(R) : null;
			if (L != null) a.left = a.inter(L);
			if (R != null) R.left = a.inter(R);
			while (LL != null && L.left >= a.inter(LL)) {
				remove(L);
				a.left = a.inter(L = LL);
				LL = hull.lower(L);
			}
			while (RR != null && R.inter(RR) <= a.inter(RR)) {
				remove(R);
				RR.left = a.inter(R = RR);
				RR = hull.higher(R);
			}
		}

		public long query(long x) {
			if(hull.size() == 0) return 0;
			Line temp = new Line(0, 0, 0);
			temp.left = x;  query = true;
			long ans = (long) hull.floor(temp).eval(x);
			query = false;  return ans;
		}

		private void remove(Line x) { hull.remove(x); }

		public int size() { return hull.size(); }

		static class Line {
			long m, b; double left = Long.MIN_VALUE;
			public Line(long mm, long x, long y) { m = mm; b = -m * x + y; }
			public Line(long mm, long bb) { m = mm; b = bb; }
			public long eval(long x) { return m * x + b; }
			public double inter(Line x) {
				return (double) (x.b - this.b) / (double) (this.m - x.m);
			}
		}
	}

	static class FS{
		BufferedReader br;
		StringTokenizer st;
		public FS() {
			br = new BufferedReader(new InputStreamReader(System.in));
		}
		String next() {
			while(st == null || !st.hasMoreElements()) {
				try {st = new StringTokenizer(br.readLine());}
				catch(Exception e) { throw null;}
			}
			return st.nextToken();
		}
		int nextInt() { return Integer.parseInt(next());}
		double nextDouble() { return Double.parseDouble(next());}
		long nextLong() { return Long.parseLong(next());}
		int[] NIA(int n) {
			int r[] = new int[n];
			for(int i = 0; i < n; i++) r[i] = nextInt();
			return r;
		}
		long[] NLA(int n) {
			long r[] = new long[n];
			for(int i = 0; i < n; i++) r[i] = nextLong();
			return r;
		}
		char[][] grid(int r, int c){
			char res[][] = new char[r][c];
			for(int i = 0; i < r; i++) {
				char l[] = next().toCharArray();
				for(int j = 0; j < c; j++) {
					res[i][j] = l[j];
				}
			}
			return res;
		}
	}

}


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashSet;
import java.util.StringTokenizer;
import java.util.TreeSet;

public class E6 {
	static PrintWriter out = new PrintWriter(System.out);
	static int M;
	static int maxN = 200001;
	static int curN;
	static Edge adj[][];
	static int curE[];
	static ArrayList<VecL[]> candidates;
	static int[] sz;
	static final boolean debug = false;
	public static void main(String[] args) {
		FS in = new FS();
		int N = in.nextInt();
		M = in.nextInt();

		ArrayDeque<Edge> es[] = new ArrayDeque[N];
		for(int i = 0; i < N; i++) es[i] = new ArrayDeque<Edge>();
		for(int i = 0; i < N-1; i++) {
			int u = in.nextInt()-1;
			int v = in.nextInt()-1;
			long m = in.nextLong();
			long b = in.nextLong();
			Edge e = new Edge(u,v,m,b);
			es[u].add(e);
			es[v].add(e);
		}

		curN = N;
		adj = new Edge[maxN][3];
		curE = new int[maxN];
		fixTree(0, -1, es);

		if(debug) {
			System.out.println("N= "+ curN);
			for(int i = 0; i < curN; i++) {
				System.out.println(i+" "+adj[i].toString());
			}
		}

		candidates = new ArrayList<>();
		sz = new int[curN];
		solve(0);

		CHT cht = new CHT(1);
		for(VecL[] cs : candidates) {
			for(VecL v : cs) {
				cht.add(v.x, v.y);
			}
		}

		for(int i = 0; i < M; i++) out.print(cht.query(i)+" ");
		out.println();
		out.close();
	}

	static void solve(int node) {
		szdfs(node, -1);
		if(sz[node] == 1) return; // base case, no edges
		Edge e = getEdgetroid(node, -1, sz[node], null);
		e.blocked = true;

		//solve on this guy
		ArrayList<VecL> left = new ArrayList<VecL>();
		ArrayList<VecL> right = new ArrayList<VecL>();
		makeLines(e.u, -1, e.m, e.b, left);
		makeLines(e.v, -1, 0, 0, right);

		VecL[] minskowski = minkowskiSum(getHull(removeDupes(left)), getHull(removeDupes(right)));
		candidates.add(minskowski);

		if(debug) {
			System.out.println("Decomp on: "+e);
			System.out.println("  Left: "+left.toString());
			System.out.println("  Right: "+right.toString());
			System.out.println("  Minskowski: "+Arrays.toString(minskowski));
		}

		//now solve on the remaining stuff
		solve(e.u);
		solve(e.v);
	}

	static void makeLines(int node, int p, long curM, long curB, ArrayList<VecL> vecs) {
		int to = 0;
		for(Edge e : adj[node]) {
			if(e == null || e.blocked || e.to(node) == p) continue;
			to++;
			makeLines(e.to(node), node, curM + e.m, curB + e.b, vecs);
		}
		if(to == 0) vecs.add(new VecL(curM, curB));
	}

	static Edge getEdgetroid(int node, int p, int totalSz, Edge curBest) {
		Edge myBest = null;
		for(Edge e : adj[node]) {
			if(e == null || e.blocked || e.to(node) == p) continue;
			if(myBest == null || myBest.getDif(totalSz) > e.getDif(totalSz)) {
				myBest = e;
			}
		}
		if(curBest != null && (myBest == null || curBest.getDif(totalSz) <= myBest.getDif(totalSz))) return curBest;
		return getEdgetroid(myBest.to(node), node, totalSz, myBest);
	}
	static void szdfs(int node, int p) {
		sz[node] = 1;
		for(Edge e : adj[node]) {
			if(e == null || e.blocked || e.to(node) == p) continue;
			szdfs(e.to(node), node);
			sz[node] += sz[e.to(node)];
		}
	}

	static void fixTree(int node, int p, ArrayDeque<Edge> es[]) {
		int cur = node;
		while(!es[node].isEmpty()) {
			if(es[node].size() <= 2) {
				while(!es[node].isEmpty()) {
					Edge e = es[node].poll();
					e.swap(node, cur);
					int to = e.to(cur);
					addEdge(cur, to, e, false, es);
					fixTree(to, cur, es);
				}
			}
			else {
				//add left edge to my current guy
				Edge e = es[node].poll();
				e.swap(node, cur);
				int to = e.to(cur);
				addEdge(cur, to, e, false, es);
				fixTree(to, cur, es);

				int next = curN++;
				Edge filler = new Edge(cur, next, 0, 0);
				addEdge(cur, next, filler, true, es);
				cur = next;
			}
		}
	}
	static void addEdge(int a, int b, Edge e, boolean filler, ArrayDeque<Edge> es[]) {
		adj[a][curE[a]++] = e;
		adj[b][curE[b]++] = e;
		if(!filler) es[b].remove(e);
	}

	static class Edge{
		int u,v;
		long m,b;
		boolean blocked;
		public Edge(int uu, int vv, long mm, long bb) {
			u=uu; v=vv; m=mm; b=bb;
			blocked = false;
		}
		int to(int node) { return u^v^node; }
		void swap(int from, int to) {
			if(u == from) u = to;
			else if(v == from) v = to;
			else throw null;
		}
		int getDif(int totalSz) {
			int s1 = Math.min(sz[u], sz[v]);
			int s2 = totalSz - Math.min(sz[u], sz[v]);
			return Math.abs(s1-s2);
		}
		@Override
		public String toString() {
			return "[u="+u+" v="+v+" m="+m+" b="+b+"]";
		}
	}

	// Computes the convex hull of the Minkowski sum of 2 convex polygons.
	// Polygons must be in CCW order and returns the sum in same order
	// O(N + M) where N and M are the sizes of the two polygons
	public static VecL[] minkowskiSum(VecL[] c1, VecL[] c2) {
		int n = c1.length, m = c2.length;
		if(n == 1) return simple(c1, c2);
		if(m == 1) return simple(c2, c1);
		VecL[] hull = new VecL[n+m];
		SegL[] s1 = toSeg(c1);
		SegL[] s2 = toSeg(c2);
		int nst = getSt(s1), mst = getSt(s2);
		int rId = 0, ni = nst, mi = mst;
		hull[rId++] = s1[ni].from.add(s2[mi].from);
		while(rId < n+m) {
			if(mi == -1 || (ni != -1 && c1[ni].radialCompare(c2[mi]) <= 0)) {
				hull[rId] = hull[rId++-1].add(s1[ni++].dir);
				if(ni >= n) ni = 0;
				if(ni == nst) ni = -1;
			}
			else {
				hull[rId] = hull[rId++-1].add(s2[mi++].dir);
				if(mi >= m) mi = 0;
				if(mi == mst) mi = -1;
			}
		}
		VecL[] res = new VecL[n+m];
		int cId = 0;
		for(int i = 0; i < hull.length; i++) {
			if(valid(hull[(i-1+hull.length)%hull.length], hull[i], hull[(i+1)%hull.length])) res[cId++] = hull[i];
		}

		return Arrays.copyOf(res, cId);
	}

	static boolean valid(VecL a, VecL b, VecL c) {
		VecL d1 = b.sub(a), d2 = c.sub(b);
		long cross = d1.cross(d2), dot = d1.dot(d2);
		return cross != 0 || (cross == 0 && dot < 0);
	}

	static VecL[] simple(VecL[] pnt, VecL[] c) {
		VecL[] res = new VecL[c.length];
		for(int i = 0; i < c.length; i++) res[i] = c[i].add(pnt[0]);
		return res;
	}

	static SegL[] toSeg(VecL pnts[]) {
		SegL[] res = new SegL[pnts.length];
		for(int i = 0; i < pnts.length; i++) {
			res[i] = new SegL(pnts[i], pnts[(i+1)%pnts.length]);
		}
		return res;
	}

	static boolean better(int i1, int i2, SegL c1[], SegL c2[]) {
		if(i1 == -1) return false;
		if(i2 == -1) return true;
		return c1[i1].dir.radialCompare(c2[i2].dir) <= 0;
	}

	static int getSt(SegL[] segs) {
		if(segs.length == 1) return -1;
		if(segs.length == 2) {
			if(segs[0].dir.y > 0 || (segs[0].dir.y == 0 && segs[0].dir.x > 0)) return 0;
			return 1;
		}
		for(int i = 0; i < segs.length; i++) {
			SegL prev = i == 0 ? segs[segs.length-1] : segs[i-1];
			SegL cur = segs[i];
			if(cur.dir.y >= 0 && prev.dir.y < 0) return i;
		}
		return -1;
	}

	public static VecL[] removeDupes(ArrayList<VecL> points) {
		HashSet<VecL> set=new HashSet<>();
		for (VecL v:points)
			set.add(v);
		int counter=0;
		VecL res[] = new VecL[set.size()];
		for (VecL v:set) res[counter++]=v;
		return res;
	}
	// returns the hull in CCW order
	public static VecL[] getHull(VecL[] points) {
		points=points.clone();
		Arrays.sort(points);
		if (points.length<3)
			return points;
		int n=points.length, j=2, k=2;
		VecL[] lo=new VecL[n], up=new VecL[n];
		lo[0]=points[0];
		lo[1]=points[1];
		for (int i=2; i<n; i++) {
			VecL p=points[i];
			while (j>1&&!right(lo[j-2], lo[j-1], p)) j--;
			lo[j++]=p;
		}
		up[0]=points[n-1];
		up[1]=points[n-2];
		for (int i=n-3; i>=0; i--) {
			VecL p=points[i];
			while (k>1&&!right(up[k-2], up[k-1], p)) k--;
			up[k++]=p;
		}

		VecL[] res=new VecL[j+k-2];
		for (int i=0; i<k; i++) res[i]=up[i];
		for (int i=1; i<j-1; i++) res[k+i-1]=lo[i];
		return res;
	}

	// check if a->b->c are in the right order
	static boolean right(VecL a, VecL b, VecL c) {
		return b.sub(a).cross(c.sub(a))>0;
	}

	static class VecL implements Comparable<VecL>{
		long x,y;
		public VecL(long xx, long yy) {
			x=xx;
			y=yy;
		}
		public VecL add(VecL o) { return new VecL(x+o.x, y+o.y);}
		public VecL sub(VecL o) { return new VecL(x-o.x, y-o.y);}
		public long cross(VecL o) { return x*o.y - y*o.x;}
		public long dot(VecL o) { return x*o.x + y*o.y;}
		public int quadrant() {
			if (x==0||y==0)
				if (y==0)
					if (x>=0)
						return 1;
					else
						return 3;
				else
					if (y>=0)
						return 2;
					else
						return 4;
			if (x>0)
				if (y>0)
					return 1;
				else
					return 4;
			else
				if (y>0)
					return 2;
				else
					return 3;
		}

		public int radialCompare(VecL o) {
			if (quadrant()==o.quadrant())
				return -Long.signum(cross(o));
			return Integer.compare(quadrant(), o.quadrant());
		}
		@Override
		public int compareTo(VecL o) {
			if(x!=o.x) return Long.compare(x, o.x);
			return Long.compare(y, o.y);
		}
		@Override
		public String toString() {
			return "("+x+","+y+")";
		}
		public int hashCode() {
			return Long.hashCode(x<<13^(y*57));
		}

		public boolean equals(Object oo) {
			VecL o=(VecL)oo;
			return x==o.x&&y==o.y;
		}
	}

	static class SegL{
		VecL from, to, dir;
		public SegL(VecL a, VecL b) {
			from=a;
			to=b;
			dir = to.sub(from);
		}
		@Override
		public String toString() {
			return "["+from+" -> "+to+"]";
		}
	}

	static class CHT {
		TreeSet<Line> hull;
		int type;  boolean query  = false;
		Comparator<Line> comp = new Comparator<Line>() {
			public int compare(Line a, Line b) {
				if (!query) return type * Long.compare(a.m, b.m);
				if (a.left == b.left) return Long.compare(a.m, b.m);
				return Double.compare(a.left, b.left);
			}
		};
		// -1 for min; +1 for max
		public CHT(int typee) { type = typee;  hull = new TreeSet<>(comp); }

		public void add(long m, long b) { add(new Line(m, b)); }

		public void add(Line a) {
			Line[] LR = { hull.lower(a), hull.ceiling(a) };
			for (int i = 0; i < 2; i++)
				if (LR[i] != null && LR[i].m == a.m) {
					if (type == 1 && LR[i].b >= a.b) return;
					if (type == -1 && LR[i].b <= a.b) return;
					remove(LR[i]);
				}
			hull.add(a);
			Line L = hull.lower(a), R = hull.higher(a);
			if (L != null && R != null && a.inter(R) <= R.left) {
				hull.remove(a);
				return;
			}
			Line LL = (L != null) ? hull.lower(L) : null;
			Line RR = (R != null) ? hull.higher(R) : null;
			if (L != null) a.left = a.inter(L);
			if (R != null) R.left = a.inter(R);
			while (LL != null && L.left >= a.inter(LL)) {
				remove(L);
				a.left = a.inter(L = LL);
				LL = hull.lower(L);
			}
			while (RR != null && R.inter(RR) <= a.inter(RR)) {
				remove(R);
				RR.left = a.inter(R = RR);
				RR = hull.higher(R);
			}
		}

		public long query(long x) {
			if(hull.size() == 0) return 0;
			Line temp = new Line(0, 0, 0);
			temp.left = x;  query = true;
			long ans = (long) hull.floor(temp).eval(x);
			query = false;  return ans;
		}

		private void remove(Line x) { hull.remove(x); }

		public int size() { return hull.size(); }

		static class Line {
			long m, b; double left = Long.MIN_VALUE;
			public Line(long mm, long x, long y) { m = mm; b = -m * x + y; }
			public Line(long mm, long bb) { m = mm; b = bb; }
			public long eval(long x) { return m * x + b; }
			public double inter(Line x) {
				return (double) (x.b - this.b) / (double) (this.m - x.m);
			}
		}
	}

	static class FS{
		BufferedReader br;
		StringTokenizer st;
		public FS() {
			br = new BufferedReader(new InputStreamReader(System.in));
		}
		String next() {
			while(st == null || !st.hasMoreElements()) {
				try {st = new StringTokenizer(br.readLine());}
				catch(Exception e) { throw null;}
			}
			return st.nextToken();
		}
		int nextInt() { return Integer.parseInt(next());}
		double nextDouble() { return Double.parseDouble(next());}
		long nextLong() { return Long.parseLong(next());}
		int[] NIA(int n) {
			int r[] = new int[n];
			for(int i = 0; i < n; i++) r[i] = nextInt();
			return r;
		}
		long[] NLA(int n) {
			long r[] = new long[n];
			for(int i = 0; i < n; i++) r[i] = nextLong();
			return r;
		}
		char[][] grid(int r, int c){
			char res[][] = new char[r][c];
			for(int i = 0; i < r; i++) {
				char l[] = next().toCharArray();
				for(int j = 0; j < c; j++) {
					res[i][j] = l[j];
				}
			}
			return res;
		}
	}

}


import java.util.InputMismatchException;
import java.io.*;
import java.util.*;

/**
 * Generated by Contest helper plug-in
 * Actual solution is at the bottom
 */
public class Main {
    public static void main(String[] args) {
        InputReader in = new StreamInputReader(System.in);
        PrintWriter out = new PrintWriter(System.out);
        run(in, out);
    }

    public static void run(InputReader in, PrintWriter out) {
        Solver solver = new Move();
        solver.solve(1, in, out);
        Exit.exit(in, out);
    }
}

class StreamInputReader extends InputReader {
    private InputStream stream;
    private byte[] buf = new byte[1024];
    private int curChar, numChars;

    public StreamInputReader(InputStream stream) {
        this.stream = stream;
        curChar = 0;
    }

    public int read() {
        if (numChars == -1)
            throw new InputMismatchException();
        if (curChar >= numChars) {
            curChar = 0;
            try {
                numChars = stream.read(buf);
            } catch (IOException e) {
                throw new InputMismatchException();
            }
            if (numChars <= 0)
                return -1;
        }
        return buf[curChar++];
    }

    @Override
    public void close() {
        try {
            stream.close();
        } catch (IOException ignored) {
        }
    }
}

abstract class InputReader {
    private boolean finished = false;

    public abstract int read();

    public String nextToken() {
        int c = read();
        while (isSpaceChar(c))
            c = read();
        StringBuffer res = new StringBuffer();
        do {
            res.appendCodePoint(c);
            c = read();
        } while (!isSpaceChar(c));
        return res.toString();
    }
    private boolean isSpaceChar(int c) {
        return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
    }

    public void setFinished(boolean finished) {
        this.finished = finished;
    }

    public abstract void close();
}

interface Solver {
    public void solve(int testNumber, InputReader in, PrintWriter out);
}

class Exit {
    private Exit() {
    }

    public static void exit(InputReader in, PrintWriter out) {
        in.setFinished(true);
        in.close();
        out.close();
    }
}

class Move implements Solver {

    Vector<String> ans ;

    void print(int i0, int j0, int i1, int j1) {
        if (i0 == i1) {
            int mn = Math.min(j0, j1);
            String p[] = H.split(" ");
            for (int j = 0; j < p.length; ++j) {
                if (p[j].equals("D")) {
                    ans.add("D"+(mn+1));
                } else {
                    ans.add(p[j]+(i0+1));
                }
            }
        } else {
            int mx = Math.max(i0, i1);
            String p[] = V.split(" ");
            for (int j = 0; j < p.length; ++j) {
                if (p[j].equals("R")) {
                    ans.add("R"+(mx+1));
                } else {
                    ans.add(p[j]+(j0+1));
                }
            }
        }
    }
    static final String H = "D L D R D L D R D L D R D";
    static final String V = "R D R U R D R U R D R U R";
    public void solve(int testNumber, InputReader in, PrintWriter out) {

        String H = "D L D R D L D R D L D R D";//swap, (i, j) -> (i, j + 1)/

        //
        //                                       // Uj Li Ri
        String V = "R D R U R D R U R D R U R"; // swap (i, j) (i + 1, j)
                                                // R(i+1), Down up -> j

        ans = new Vector<String> () ;
        //build();
        char s[] = new char[36];
        for (int i = 0; i <= 9; ++i) {
            s[i] = (char)(i + '0');
        }
        for (int i = 0; i < 26; ++i) {
            s[i + 10] = (char)(i + 'A');
        }
        char tmp[][] = new char[6][6];
        int p = 0;
        for (int i = 0; i < s.length; ++i) {
            tmp[p / 6][p % 6] = s[i];
            p ++ ;
        }
        State start = new State(tmp);

        char r[][] = new char[6][];
        for (int i =0 ; i < 6; ++i)
            r[i] = in.nextToken().toCharArray();
        State cur = new State(r);

        HashMap<Character, P> pointer = new HashMap<Character, P> ();
        for (int i = 0; i < 6; ++i)
            for (int j = 0; j < 6; ++j)
                pointer.put(cur.s[i][j], new P(j, i));

        while (!start.equals(cur)) {
            for (int i = 0; i < 6; ++i)
                for (int j = 0; j < 6; ++j) {
                    if (start.s[i][j] != cur.s[i][j])  {
                        while (start.s[i][j] != cur.s[i][j]) {
                            P tt = pointer.get(start.s[i][j]);
                            int pi = tt.y;
                            int pj = tt.x;
                            int dj = (j - pj == 0 ? 0 : (j - pj) / Math.abs(j - pj));
                            int di = (i - pi == 0 ? 0 : (i - pi) / Math.abs(i - pi));
                            int npi = -1, npj = -1;
                            if (di != 0) {
                                npi = pi + di;
                                npj = pj ;
                            } else if (dj != 0) {
                                npi = pi;
                                npj = pj + dj;
                            } else throw new RuntimeException();
                            print(npi, npj, pi, pj);
                            char ch = cur.s[npi][npj];
                            cur.s[npi][npj] = cur.s[pi][pj];
                            cur.s[pi][pj] = ch;
                            pointer.put(cur.s[npi][npj], new P(npj, npi));
                            pointer.put(cur.s[pi][pj], new P(pj, pi));
                        }
                    }
                }
        }

        cur = new State(r);
        out.print(ans.size() + "\n");
        for (String str : ans) {
            out.println(str);
        /*    char ch = str.charAt(0);
            int dig = str.charAt(1) - '1';
            if (ch == 'D') cur = cur.rotateDown(dig);
            else if (ch == 'U') cur = cur.rotateUp(dig);
            else if (ch == 'R') cur = cur.rotateRight(dig);
            else if (ch == 'L') cur = cur.rotateLeft(dig);*/
        }
      //  out.print("res : \n");
      //  out.print(cur);

    }
    class P {
        int x, y;

        P(int x, int y) {
            this.x = x;
            this.y = y;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof P)) return false;

            P p = (P) o;

            if (x != p.x) return false;
            if (y != p.y) return false;

            return true;
        }

        @Override
        public int hashCode() {
            int result = x;
            result = 31 * result + y;
            return result;
        }
    }

    class State {
        char s[][] ;

        State(char[][] s) {
            this.s = new char[s.length][];
            for (int i = 0; i < s.length; ++i)
                this.s[i] = s[i].clone();
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;

            State tmp = (State) o;
            for (int i =0 ; i < 6; ++i)
                for (int j =0 ; j < 6; ++j)
                    if (this.s[i][j] != tmp.s[i][j]) return false;
            return true;
        }

        @Override
        public int hashCode() {
            int r = 1;
            for (int i = 0; i < 6; ++i)
                for (int j = 0; j < 6; ++j)
                    r = 31 * r + (s[i][j] - '0' + 1);
            return r;
        }

        @Override
        public String toString() {
            String tmp = "";
            for (int i =0 ; i < 6; ++i) {
                tmp += Arrays.toString(this.s[i]) + "\n";
            }
            return tmp;
        }
    }
}


import java.io.*;
import java.util.*;

public class Main {
	static Scanner in;
	static PrintWriter out;
//	static StreamTokenizer in; static int next() throws Exception {in.nextToken(); return (int) in.nval;}
    static PrintWriter sout = new PrintWriter(System.out);

    static void sout(int[][] x) {
    	for (int[] xx : x) {
    		for (int xxx : xx) System.out.print(xxx + " ");
			System.out.println();
    	}
    	System.out.println();
    }

    static void sout(int[] x) {
    	for (int xxx : x) System.out.print(xxx + " ");
		System.out.println();
	}

	static int[][] a;
	static int n = 6;
	static ArrayList<String> answ;

	static void shift(int line, boolean hor, boolean plus) {
		int d = plus ? 1 : -1;
		if (hor) {
			int[] y = new int[n];
			for (int i = 0; i < n; i++) y[(i + d + n) % n] = a[line][i];
			for (int i = 0; i < n; i++) a[line][i] = y[i];
			answ.add((plus ? "R" : "L") + (line + 1));
		} else {
			int[] y = new int[n];
			for (int i = 0; i < n; i++) y[(i + d + n) % n] = a[i][line];
			for (int i = 0; i < n; i++) a[i][line] = y[i];
			answ.add((plus ? "D" : "U") + (line + 1));
		}
	}

	static void rotate(int x, int y, boolean right, boolean down, boolean clock) {
		if (clock ^ right ^ down) {
			shift(x, false, !down);
			shift(y, true, !right);
			shift(x, false, down);
			shift(y, true, right);
		} else {
			shift(y, true, !right);
			shift(x, false, !down);
			shift(y, true, right);
			shift(x, false, down);
		}
	}

	static void up(int x, int y) {
		rotate(x, y, true, false, true);
	}

	static void down(int x, int y) {
		rotate(x, y, true, true, false);
	}

	static void left(int x, int y) {
		rotate(x, y, false, true, false);
	}

	static void right(int x, int y) {
		rotate(x, y, true, true, true);
	}

	public static void main(String[] args) throws Exception {
		in = new Scanner(System.in);
		out = new PrintWriter(System.out);
//		in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));

		answ = new ArrayList<String>();

		a = new int[n][n];
		for (int i = 0; i < n; i++) {
			String s = in.next();
			for (int j = 0; j < n; j++) {
				if ('0' <= s.charAt(j) && s.charAt(j) <= '9') a[i][j] = s.charAt(j) - '0';
				else a[i][j] = s.charAt(j) - 'A' + 10;
			}
		}

		int[][] aa = new int[n][n];
		for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) aa[i][j] = a[i][j];

		int[][] g = new int[n][n];
		int[] gx = new int[n*n];
		int[] gy = new int[n*n];
		int count = 0;
		for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) {
			g[i][j] = count;
			gx[count] = j;
			gy[count] = i;
			count++;
		}
		for (int index = 0;; index++) {

		answ = new ArrayList<String>();
		for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) a[i][j] = aa[i][j];

		if (index > 0) {
			int cnt = ((int)(Math.random() * 1e9)) % 100;
			for (int i = 0; i < cnt; i++) {
				int ii = ((int)(Math.random() * 1e9)) % 6;
				int jj1 = ((int)(Math.random() * 1e9)) % 2;
				int jj2 = ((int)(Math.random() * 1e9)) % 2;
				shift(ii, jj1 == 0, jj2 == 0);
			}
		}
//		sout(a);
//		System.out.println("!!!");

		for (int i = 0; i < 4*n; i++) {
			while (true) {
//				sout(a);
				int x = 0;
				int y = 0;
				F: for (; x < n; x++) for (y = 0; y < n; y++) {
					if (a[y][x] == i) break F;
				}
//				System.out.println(x + " " + y + " " + a[x][y] + " " + a[1][1]);
				if (g[y][x] == i) break;
				if (x != gx[i]) {
					if (y == 5) rotate(x, y, false, false, true);
					else left(x, y);
				}
				else up(x, y);
			}
		}

//		System.out.println("!!! 24");

		for (int i = 0; i < 4; i++) for (int t = 4*n + i; t <= 5*n + i; t += n) {
//			System.out.println(t);
//			sout(a);
			while (true) {
//				sout(a);
				int x = 0;
				int y = 0;
				F: for (; x < n; x++) for (y = 0; y < n; y++) if (a[y][x] == t) break F;
				if (g[y][x] == t) break;

				if (y != gy[t]) {
					if (x == 5) {
						if (y < gy[t]) rotate(x, y, false, true, true);
						else rotate(x, y, false, false, false);
					} else {
						if (y < gy[t]) rotate(x, y, true, true, false);
						else rotate(x, y, true, false, true);
					}
				} else {
					if (y == 4) rotate(x, y, false, true, false);
					else rotate(x, y, false, false, true);
				}
			}
		}
//		System.out.println("!!!");

/*		while (a[4][4] != 28 || a[4][5] != 29 || a[5][4] != 34 || a[5][5] != 35) {
			int i = ((int)(Math.random() * 1e9)) % 4;
			int j = ((int)(Math.random() * 1e9)) % 2;
			if (i == 0) rotate(4, 4, true, true, j == 0);
			if (i == 1) rotate(4, 5, true, false, j == 0);
			if (i == 2) rotate(5, 4, false, true, j == 0);
			if (i == 3) rotate(5, 5, false, false, j == 0);

			sout(a);
		}*/

		int x = 0;
		int y = 0;
		F: for (x = 0; x < n; x++) for (y = 0; y < n; y++) if (a[y][x] == 28) break F;
		if (x == 5 && y == 5) rotate(x, y, false, false, true);
		F: for (x = 0; x < n; x++) for (y = 0; y < n; y++) if (a[y][x] == 28) break F;
		if (x == 5) rotate(x, y, false, true, false);
		F: for (x = 0; x < n; x++) for (y = 0; y < n; y++) if (a[y][x] == 28) break F;
		if (y == 5) rotate(x, y, true, false, true);

		while (a[5][5] != g[5][5]) rotate(5, 5, false, false, true);

		if (a[5][4] == 34) break;

		}

		out.println(answ.size());
		for (String s : answ) out.println(s);

//		sout(a);

		out.close();
	}
}


import java.io.*;
import java.util.*;

public class Main {
	static Scanner in;
	static PrintWriter out;
//	static StreamTokenizer in; static int next() throws Exception {in.nextToken(); return (int) in.nval;}
    static PrintWriter sout = new PrintWriter(System.out);

    static void sout(int[][] x) {
    	for (int[] xx : x) {
    		for (int xxx : xx) System.out.print(xxx + " ");
			System.out.println();
    	}
    	System.out.println();
    }

    static void sout(int[] x) {
    	for (int xxx : x) System.out.print(xxx + " ");
		System.out.println();
	}

	static int[][] a;
	static int n = 6;
	static ArrayList<String> answ;

	static void shift(int line, boolean hor, boolean plus) {
		int d = plus ? 1 : -1;
		if (hor) {
			int[] y = new int[n];
			for (int i = 0; i < n; i++) y[(i + d + n) % n] = a[line][i];
			for (int i = 0; i < n; i++) a[line][i] = y[i];
			answ.add((plus ? "R" : "L") + (line + 1));
		} else {
			int[] y = new int[n];
			for (int i = 0; i < n; i++) y[(i + d + n) % n] = a[i][line];
			for (int i = 0; i < n; i++) a[i][line] = y[i];
			answ.add((plus ? "D" : "U") + (line + 1));
		}
	}

	static void rotate(int x, int y, boolean right, boolean down, boolean clock) {
		if (clock ^ right ^ down) {
			shift(x, false, !down);
			shift(y, true, !right);
			shift(x, false, down);
			shift(y, true, right);
		} else {
			shift(y, true, !right);
			shift(x, false, !down);
			shift(y, true, right);
			shift(x, false, down);
		}
	}

	static void up(int x, int y) {
		rotate(x, y, true, false, true);
	}

	static void down(int x, int y) {
		rotate(x, y, true, true, false);
	}

	static void left(int x, int y) {
		rotate(x, y, false, true, false);
	}

	static void right(int x, int y) {
		rotate(x, y, true, true, true);
	}

	public static void main(String[] args) throws Exception {
		in = new Scanner(System.in);
		out = new PrintWriter(System.out);
//		in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));

		answ = new ArrayList<String>();

		a = new int[n][n];
		for (int i = 0; i < n; i++) {
			String s = in.next();
			for (int j = 0; j < n; j++) {
				if ('0' <= s.charAt(j) && s.charAt(j) <= '9') a[i][j] = s.charAt(j) - '0';
				else a[i][j] = s.charAt(j) - 'A' + 10;
			}
		}

		int[][] g = new int[n][n];
		int[] gx = new int[n*n];
		int[] gy = new int[n*n];
		int count = 0;
		for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) {
			g[i][j] = count;
			gx[count] = j;
			gy[count] = i;
			count++;
		}

//		sout(a);
//		System.out.println("!!!");

		for (int i = 0; i < 4*n; i++) {
			while (true) {
//				sout(a);
				int x = 0;
				int y = 0;
				F: for (; x < n; x++) for (y = 0; y < n; y++) {
					if (a[y][x] == i) break F;
				}
//				System.out.println(x + " " + y + " " + a[x][y] + " " + a[1][1]);
				if (g[y][x] == i) break;
				if (x != gx[i]) {
					if (y == 5) rotate(x, y, false, false, true);
					else left(x, y);
				}
				else up(x, y);
			}
		}

//		System.out.println("!!! 24");

		for (int i = 0; i < 4; i++) for (int t = 4*n + i; t <= 5*n + i; t += n) {
//			System.out.println(t);
//			sout(a);
			while (true) {
				int x = 0;
				int y = 0;
				F: for (; x < n; x++) for (y = 0; y < n; y++) if (a[y][x] == t) break F;
				if (g[y][x] == t) break;

				if (y != gy[t]) {
					if (x == 5) {
						if (y < gy[t]) rotate(x, y, false, true, true);
						else rotate(x, y, false, false, false);
					} else {
						if (y < gy[t]) rotate(x, y, true, true, false);
						else rotate(x, y, true, false, true);
					}
				} else {
					if (y == 4) rotate(x, y, false, true, false);
					else rotate(x, y, false, false, true);
				}
			}
		}

		while (a[4][4] != 28 || a[4][5] != 29 || a[5][4] != 34 || a[5][5] != 35) {
			int i = ((int)(Math.random() * 1e9)) % 4;
			int j = ((int)(Math.random() * 1e9)) % 2;
			if (i == 0) rotate(4, 4, true, true, j == 0);
			if (i == 1) rotate(4, 5, true, false, j == 0);
			if (i == 2) rotate(5, 4, false, true, j == 0);
			if (i == 3) rotate(5, 5, false, false, j == 0);
		}

/*		int x = 0;
		int y = 0;
		F: for (x = 0; x < n; x++) for (y = 0; y < n; y++) if (a[y][x] == 28) break F;
		if (x == 5 && y == 5) rotate(x, y, false, false, true);
		F: for (x = 0; x < n; x++) for (y = 0; y < n; y++) if (a[y][x] == 28) break F;
		if (x == 5) rotate(x, y, false, true, false);
		F: for (x = 0; x < n; x++) for (y = 0; y < n; y++) if (a[y][x] == 28) break F;
		if (y == 5) rotate(x, y, true, false, true);

//		sout(a);

		while (a[5][5] != g[5][5]) rotate(5, 5, false, false, true);*/

		out.println(answ.size());
		for (String s : answ) out.println(s);

//		sout(a);

		out.close();
	}
}


// package cf1181;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.BinaryOperator;
import java.util.function.Function;

import static java.util.Comparator.comparingInt;

public class CFE2 {
    private static final String INPUT = "14\n" +
            "4 17 6 20\n" +
            "9 17 10 20\n" +
            "12 17 20 18\n" +
            "10 15 11 16\n" +
            "0 11 3 20\n" +
            "10 13 11 14\n" +
            "11 4 16 15\n" +
            "11 18 19 20\n" +
            "4 5 10 15\n" +
            "10 4 11 13\n" +
            "0 0 16 3\n" +
            "17 0 20 16\n" +
            "0 7 3 8\n" +
            "0 4 3 6";
    private static final int MOD = 1_000_000_007;

    private PrintWriter out;
    private FastScanner sc;

    public static void main(String[] args) {
        new CFE2().run();
    }

    public void run() {
        sc = new FastScanner(oj ? System.in : new ByteArrayInputStream(INPUT.getBytes()));
        out = new PrintWriter(System.out);

        long s = System.currentTimeMillis();
        solve();
        out.flush();
        tr(System.currentTimeMillis() - s + "ms");
    }

    static class Rect {
        int x1, y1, x2, y2;
        boolean used;

        public Rect(int x1, int y1, int x2, int y2) {
            this.x1 = x1;
            this.y1 = y1;
            this.x2 = x2;
            this.y2 = y2;
        }

        @Override
        public String toString() {
            return "{" + x1 + "," + y1 + "-" + x2 + "," + y2 + "}";
        }
    }

    static class Node {
        private Rect rect;
        private Node next;

        public Node(Rect rect) {
            this.rect = rect;
        }
    }

    static interface AreaFunc {
        int area(int area, Rect rect);

        default int _area(Rect rect) {
            int a1 = area(-1, rect);
            int a2 = area(Integer.MAX_VALUE, rect);

            return (a1 > -1) ? a1 : a2;
        }
    }

    static class Rects {
        private final AreaFunc areaFunc;
        private final BiPredicate<Integer, Rect> isSpace;

        Node root;
        Node curr;

        int currIdx;
        int area;

        public Rects(List<Rect> rects, Comparator<Rect> cmp, AreaFunc areaFunc, BiPredicate<Integer, Rect> isSpace) {
            this.areaFunc = areaFunc;
            this.isSpace = isSpace;
            rects.sort(cmp);
            root = new Node(rects.get(0));
            Node cur = root;
            for (int i = 1; i < rects.size(); i++) {
                Rect rect = rects.get(i);
                Node node = new Node(rect);
                cur.next = node;
                cur = node;
            }

            init();
        }

        private void init() {
            while (root.rect.used) root = root.next;
            curr = root;
            area = areaFunc._area(root.rect);
            currIdx = 1;
        }

        public void next() {
            Node prev = curr;
            Node next = prev.next;
            while (next.rect.used) {
                next = next.next;
            }
            prev.next = next;
            curr = next;
            currIdx++;
        }

        public boolean isSpace() {
            boolean test = isSpace.test(area, curr.rect);
            if (!test) area = areaFunc.area(area, curr.rect);
            return test;
        }

        List<Rect> drain() {
            Node node = root;
            List<Rect> res = new ArrayList<>(currIdx-1);
            for (int i = 1; i < currIdx; i++) {
                res.add(node.rect);
                node = node.next;
            }
            return res;
        }

        @Override
        public String toString() {
            Node node = root;
            StringBuilder res = new StringBuilder();
            while (node != null) {
                res.append(node.rect).append(" ");
                node = node.next;
            }
            return res.toString();
        }
    }

    static class Solver {
        int size;
        Rects[] rects = new Rects[4];

        public Solver(List<Rect> list) {
            size = list.size();
            if (size >= 4) {
                rects[0] = new Rects(list, comparingInt((Rect r) -> r.x1), (area, r) -> Math.max(area, r.x2), (a, r) -> a <= r.x1);
                rects[1] = new Rects(list, comparingInt((Rect r) -> -r.x2), (area, r) -> Math.min(area, r.x1), (a, r) -> a >= r.x2);
                rects[2] = new Rects(list, comparingInt((Rect r) -> r.y1), (area, r) -> Math.max(area, r.y2), (a, r) -> a <= r.y1);
                rects[3] = new Rects(list, comparingInt((Rect r) -> -r.y2), (area, r) -> Math.min(area, r.y1), (a, r) -> a >= r.y2);
            } else {
                rects[0] = new Rects(list, comparingInt((Rect r) -> r.x1), (area, r) -> Math.max(area, r.x2), (a, r) -> a <= r.x1);
            }
        }

        boolean solve() {
            LOOP: while (size >= 4 && (rects[0].currIdx << 1) <= size) {
                for (int i = 0; i < 4; i++) {
                    Rects rect = rects[i];
                    rect.next();
                    if (rect.isSpace()) {
                        List<Rect> drain = rect.drain();
                        size -= drain.size();
                        boolean solve = new Solver(drain).solve();
                        if (!solve) return false;

                        for (int j = 0; j < 4; j++) {
                            rects[j].init();
                        }
                        continue LOOP;
                    }
                }
            }

            if (size < 4) {
                for (Node node = rects[0].root; node != null; node = node.next) {
                    node.rect.used = true;
                }
                return true;
            }
            return false;
        }
    }

    public void solve() {
        int n = sc.nextInt();
        List<Rect> list = new ArrayList<>(n);
        for (int i = 0; i < n; i++) {
            Rect rect = new Rect(sc.nextInt(), sc.nextInt(), sc.nextInt(), sc.nextInt());
            list.add(rect);
        }

        Solver solver = new Solver(list);
        System.out.println(solver.solve() ? "YES" : "NO");

    }

//********************************************************************************************
//********************************************************************************************
//********************************************************************************************

    static class SolutionFailedException extends Exception {
        int code;

        public SolutionFailedException(int code) {
            this.code = code;
        }
    }

    private static void shuffle(int[] array) {
        Random random = new Random();
        for (int i = array.length - 1; i > 0; i--) {
            int index = random.nextInt(i + 1);
            int temp = array[index];
            array[index] = array[i];
            array[i] = temp;
        }
    }

    /**
     * If searched element doesn't exist, returns index of first element which is bigger than searched value.

     * If searched element is bigger than any array element function returns first index after last element.

     * If searched element is lower than any array element function returns index of first element.

     * If there are many values equals searched value function returns first occurrence.

     */
    private static int lowerBound(long[] arr, long key) {
        int lo = 0;
        int hi = arr.length - 1;
        while (lo < hi) {
            int mid = (lo + hi) / 2;
            if (key <= arr[mid]) {
                hi = mid - 1;
            } else {
                lo = mid + 1;
            }
        }
        return arr[lo] < key ? lo + 1 : lo;
    }

    /**
     * Returns index of first element which is grater than searched value.
     * If searched element is bigger than any array element, returns first index after last element.
     */
    private static int upperBound(long[] arr, long key) {
        int lo = 0;
        int hi = arr.length - 1;
        while (lo < hi) {
            int mid = (lo + hi) / 2;
            if (key >= arr[mid]) {
                lo = mid + 1;
            } else {
                hi = mid;
            }
        }
        return arr[lo] <= key ? lo + 1 : lo;
    }

    private static int ceil(double d) {
        int ret = (int) d;
        return ret == d ? ret : ret + 1;
    }

    private static int round(double d) {
        return (int) (d + 0.5);
    }

    private static int gcd(int a, int b) {
        BigInteger b1 = BigInteger.valueOf(a);
        BigInteger b2 = BigInteger.valueOf(b);
        BigInteger gcd = b1.gcd(b2);
        return gcd.intValue();
    }

    private static long gcd(long a, long b) {
        BigInteger b1 = BigInteger.valueOf(a);
        BigInteger b2 = BigInteger.valueOf(b);
        BigInteger gcd = b1.gcd(b2);
        return gcd.longValue();
    }

    private int[] readIntArray(int n) {
        int[] res = new int[n];
        for (int i = 0; i < n; i++) {
            res[i] = sc.nextInt();
        }
        return res;
    }

    private long[] readLongArray(int n) {
        long[] res = new long[n];
        for (int i = 0; i < n; i++) {
            res[i] = sc.nextLong();
        }
        return res;
    }

    @SuppressWarnings("unused")
    static class FastScanner {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;

        FastScanner(InputStream stream) {
            this.stream = stream;
        }

        int read() {
            if (numChars == -1)
                throw new InputMismatchException();
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0) return -1;
            }
            return buf[curChar++];
        }

        boolean isSpaceChar(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        boolean isEndline(int c) {
            return c == '\n' || c == '\r' || c == -1;
        }

        public int nextInt() {
            return Integer.parseInt(next());
        }

        public long nextLong() {
            return Long.parseLong(next());
        }

        public double nextDouble() {
            return Double.parseDouble(next());
        }

        public String next() {
            int c = read();
            while (isSpaceChar(c)) c = read();
            StringBuilder res = new StringBuilder();
            do {
                res.appendCodePoint(c);
                c = read();
            } while (!isSpaceChar(c));
            return res.toString();
        }

        public String nextLine() {
            int c = read();
            while (isEndline(c))
                c = read();
            StringBuilder res = new StringBuilder();
            do {
                res.appendCodePoint(c);
                c = read();
            } while (!isEndline(c));
            return res.toString();
        }

    }

    private boolean oj = System.getProperty("ONLINE_JUDGE") != null;

    private void tr(Object... o) {
        if (!oj) System.out.println(Arrays.deepToString(o));
    }
}


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Random;
import java.util.StringTokenizer;
import java.util.TreeSet;

public class StoryOfCountry {
	public static void main(String[] args) {
		FS in = new FS();
		int N = in.nextInt();
		TreeSet<Rec> hEnd = HE();
		TreeSet<Rec> hStart = HS();
		TreeSet<Rec> vEnd = VE();
		TreeSet<Rec> vStart = VS();
		for(int i = 0; i < N; i++) {
			Rec r = new Rec(in.nextInt(), in.nextInt(), in.nextInt(), in.nextInt(), i);
			hEnd.add(r); hStart.add(r); vEnd.add(r); vStart.add(r);
		}
		System.out.println(solve(0, hEnd, hStart, vEnd, vStart) ? "YES":"NO");
	}

	/* State:
	 *  0 -> can be either vertical or horizontal
	 *  1 -> has to be vertical split
	 *  2 -> has to be horizontal split
	 */
	static boolean solve(int state, TreeSet<Rec> he, TreeSet<Rec> hs, TreeSet<Rec> ve, TreeSet<Rec> vs) {
		if(he.size() <= 2) return true; // Always possible with just 2 things

		TreeSet<Rec> lhe = HE();
		TreeSet<Rec> lhs = HS();
		TreeSet<Rec> lve = VE();
		TreeSet<Rec> lvs = VS();

		TreeSet<Rec> rhe = HE();
		TreeSet<Rec> rhs = HS();
		TreeSet<Rec> rve = VE();
		TreeSet<Rec> rvs = VS();

		TreeSet<Rec> lhe2 = HE();
		TreeSet<Rec> lhs2 = HS();
		TreeSet<Rec> lve2 = VE();
		TreeSet<Rec> lvs2 = VS();

		TreeSet<Rec> rhe2 = HE();
		TreeSet<Rec> rhs2 = HS();
		TreeSet<Rec> rve2 = VE();
		TreeSet<Rec> rvs2 = VS();

		Rec lR = null;
		Rec lRS = null;
		int maxLRS = -1;
		Rec rR = null;
		Rec rRS = null;
		int minRRS = 2131231231;

		Rec lR2 = null;
		Rec lRS2 = null;
		int maxLRS2 = -1;
		Rec rR2 = null;
		Rec rRS2 = null;
		int minRRS2 = 2131231231;

		while((state != 2 && (lR == null || rR == null || lR.x2 < rR.x1)) || (state != 1 && (lR2 == null || rR2 == null || lR2.y2 < rR2.y1))) {
			//do left side
			if(state != 2 && (lR == null || rR == null || lR.x2 < rR.x1)) {
				lR = (lR == null ? he.first() : he.higher(lR));
				lhe.add(lR);
				while(true) {
					Rec next = (lRS == null ? hs.first() : hs.higher(lRS));
					if(next == null || next.x1 >= lR.x2) break;
					maxLRS = Math.max(maxLRS, next.x2);
					lRS = next;
				}
				if(lR.x2 >= maxLRS) { //found a working thing
					Rec r;
					while((r = he.higher(lR)) != null && r.x2 == lR.x2){ lhe.add(r); lR = r; }
						for(Rec rr : lhe) {
							he.remove(rr); hs.remove(rr); ve.remove(rr); vs.remove(rr);
							lhs.add(rr); lve.add(rr); lvs.add(rr);
						}
					return solve(2,lhe,lhs,lve,lvs)&&solve(0,he,hs,ve,vs);
				}

				//do right side
				rR = (rR == null ? hs.last() : hs.lower(rR));
				rhe.add(rR);
				while(true) {
					Rec next = (rRS == null ? he.last() : he.lower(rRS));
					if(next == null || next.x2 <= rR.x1) break;
					minRRS = Math.min(minRRS, next.x1);
					rRS = next;
				}
				if(rR.x1 <= minRRS) { //found a working thing
					Rec r;
					while((r = hs.lower(rR)) != null && r.x1 == rR.x1){ rhe.add(r); rR = r; }
						for(Rec rr : rhe) {
							he.remove(rr); hs.remove(rr); ve.remove(rr); vs.remove(rr);
							rhs.add(rr); rve.add(rr); rvs.add(rr);
						}
					return solve(0,he,hs,ve,vs)&&solve(2,rhe,rhs,rve,rvs);
				}
			}

			if(state != 1 && (lR2 == null || rR2 == null || lR2.y2 < rR2.y1)) {
				//do left side2
				lR2 = (lR2 == null ? ve.first() : ve.higher(lR2));
				lhe2.add(lR2);
				while(true) {
					Rec next = (lRS2 == null ? vs.first() : vs.higher(lRS2));
					if(next == null || next.y1 >= lR2.y2) break;
					maxLRS2 = Math.max(maxLRS2, next.y2);
					lRS2 = next;
				}
				if(lR2.y2 >= maxLRS2) { //found a working thing
					Rec r;
					while((r = ve.higher(lR2)) != null && r.y2 == lR2.y2){ lhe2.add(r); lR2 = r; }
						for(Rec rr : lhe2) {
							he.remove(rr); hs.remove(rr); ve.remove(rr); vs.remove(rr);
							lhs2.add(rr); lve2.add(rr); lvs2.add(rr);
						}
					return solve(1,lhe2,lhs2,lve2,lvs2)&&solve(0,he,hs,ve,vs);
				}

				//do right side2
				rR2 = (rR2 == null ? vs.last() : vs.lower(rR2));
				rhe2.add(rR2);
				while(true) {
					Rec next = (rRS2 == null ? ve.last() : ve.lower(rRS2));
					if(next == null || next.y2 <= rR2.y1) break;
					minRRS2 = Math.min(minRRS2, next.y1);
					rRS2 = next;
				}
				if(rR2.y1 <= minRRS2) { //found a working thing
					Rec r;
					while((r = vs.lower(rR2)) != null && r.y1 == rR2.y1){ rhe2.add(r); rR2 = r; }
						for(Rec rr : rhe2) {
							he.remove(rr); hs.remove(rr); ve.remove(rr); vs.remove(rr);
							rhs2.add(rr); rve2.add(rr); rvs2.add(rr);
						}
					return solve(0,he,hs,ve,vs)&&solve(1,rhe2,rhs2,rve2,rvs2);
				}
			}
		}
		return false;
	}

	static TreeSet<Rec> HE() {
		return new TreeSet<Rec>((a,b) -> (a.x2 == b.x2 ? a.id-b.id : a.x2-b.x2));
	}
	static TreeSet<Rec> HS(){
		return new TreeSet<Rec>((a,b) -> (a.x1 == b.x1 ? a.id-b.id : a.x1-b.x1));
	}
	static TreeSet<Rec> VE(){
		return new TreeSet<Rec>((a,b) -> (a.y2 == b.y2 ? a.id-b.id : a.y2-b.y2));
	}
	static TreeSet<Rec> VS(){
		return new TreeSet<Rec>((a,b) -> (a.y1 == b.y1 ? a.id-b.id : a.y1-b.y1));
	}
	static class Rec{
		int x1,y1,x2,y2,id;
		public Rec(int a, int b, int c, int d, int ii) {
			x1=a; y1=b; x2=c; y2=d;
			id=ii;
		}
	}

	static class FS{
		BufferedReader br;
		StringTokenizer st;
		public FS() {
			br = new BufferedReader(new InputStreamReader(System.in));
		}
		String next() {
			while(st == null || !st.hasMoreElements()) {
				try { st = new StringTokenizer(br.readLine());}
				catch(Exception e) { throw null;}
			}
			return st.nextToken();
		}
		int nextInt() { return Integer.parseInt(next());}
	}
}


// package cf1181;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.*;

import static java.util.Comparator.comparingInt;

public class CFE1 {
    private static final String INPUT = "4\n" +
            "0 0 1 2\n" +
            "0 2 1 3\n" +
            "1 0 2 1\n" +
            "1 1 2 3";
    private static final int MOD = 1_000_000_007;

    private PrintWriter out;
    private FastScanner sc;

    public static void main(String[] args) {
        new CFE1().run();
    }

    public void run() {
        sc = new FastScanner(oj ? System.in : new ByteArrayInputStream(INPUT.getBytes()));
        out = new PrintWriter(System.out);

        long s = System.currentTimeMillis();
        solve();
        out.flush();
        tr(System.currentTimeMillis() - s + "ms");
    }

    static class Rect {
        int x1, y1, x2, y2;

        public Rect(int x1, int y1, int x2, int y2) {
            this.x1 = x1;
            this.y1 = y1;
            this.x2 = x2;
            this.y2 = y2;
        }

        @Override
        public String toString() {
            return "{" + x1 + "," + y1 + "-" + x2 + "," + y2 + "}";
        }
    }

    public void solve() {
        int n = sc.nextInt();
        Set<Rect> set = new TreeSet<>(comparingInt((Rect r) -> r.x1).thenComparingInt(r -> r.y1));
        for (int i = 0; i < n; i++) {
            Rect rect = new Rect(sc.nextInt(), sc.nextInt(), sc.nextInt(), sc.nextInt());
            set.add(rect);
        }

        int sol = solve(set);
        System.out.println(sol == n ? "YES" : "NO");
    }

    private int solve(Set<Rect> set) {
        if (set.size() < 4) return set.size();
        if (list.size() > 4) out.println("x: " + list.size());
        return _solve(set);
    }

    static class Recter {
        int i;
        Set<Rect> set;
        Iterator<Rect> it;
        Rect rect;
        int area;

        public Recter(Set<Rect> set) {
            this.i = 1;
            this.set = set;
            it = set.iterator();
            rect = it.next();
        }

        Rect next() {
            i++;
            return rect = it.next();
        }

        int size() {
            return set.size();
        }

        Set<Rect> drain() {
            Set<Rect> res = new TreeSet<>(comparingInt((Rect r) -> r.x1).thenComparingInt(r -> r.y1));
            Iterator<Rect> resIt = set.iterator();
            for (int i = 0; i < this.i-1; i++) {
                res.add(resIt.next());
                resIt.remove();
            }

            it = set.iterator();
            rect = it.next();
            i = 1;
            return res;
        }

        void clear(Set<Rect> rects) {
            for (Rect r : rects) {
                set.remove(r);
            }
            it = set.iterator();
            rect = it.next();
            i = 1;
        }
    }

    private int _solve(Set<Rect> setX1) {
        Recter rX1 = new Recter(setX1);
        TreeSet<Rect> setX2 = new TreeSet<>(comparingInt((Rect r1) -> -r1.x2).thenComparingInt(r1 -> -r1.y2));
        setX2.addAll(setX1);
        Recter rX2 = new Recter(setX2);

        TreeSet<Rect> setY1 = new TreeSet<>(comparingInt((Rect r1) -> r1.y1).thenComparingInt(r1 -> r1.x1));
        setY1.addAll(setX1);
        Recter rY1 = new Recter(setY1);

        TreeSet<Rect> setY2 = new TreeSet<>(comparingInt((Rect r) -> -r.y2).thenComparingInt(r -> -r.x2));
        setY2.addAll(setX1);
        Recter rY2 = new Recter(setY2);

        int result = 0;
        rX1.area = rX1.rect.x2;
        rX2.area = rX2.rect.x1;
        rY1.area = rY1.rect.y2;
        rY2.area = rY1.rect.y1;
        while (rX1.size() >= 4 && (rX1.i + rX2.i) <= rX1.size()) {
            rX1.next();
            if (rX1.rect.x1 >= rX1.area) {
                int n = rX1.i - 1;
                Set<Rect> set = rX1.drain();
                rX1.area = rX1.rect.x2;

                rX2.clear(set);
                rX2.area = rX2.rect.x1;

                rY1.clear(set);
                rY1.area = rY1.rect.y2;

                rY2.clear(set);
                rY2.area = rY2.rect.y1;

                int res = solve(set);
                if (res < n) return -1_000_000;
                result += res;
                continue;
            } else {
                rX1.area = Math.max(rX1.area, rX1.rect.x2);
            }

            rX2.next();
            if (rX2.rect.x2 <= rX2.area) {
                int n = rX2.i - 1;
                Set<Rect> set = rX2.drain();
                rX2.area = rX2.rect.x1;

                rX1.clear(set);
                rX1.area = rX1.rect.x2;

                rY1.clear(set);
                rY1.area = rY1.rect.y2;

                rY2.clear(set);
                rY2.area = rY2.rect.y1;

                int res = solve(set);
                if (res < n) return -1_000_000;
                result += res;
                continue;
            } else {
                rX2.area = Math.min(rX2.area, rX2.rect.x1);
            }

            rY1.next();
            if (rY1.rect.y1 >= rY1.area) {
                int n = rY1.i - 1;
                Set<Rect> set = rY1.drain();
                rY1.area = rY1.rect.y2;

                rY2.clear(set);
                rY2.area = rY2.rect.y1;

                rX1.clear(set);
                rX1.area = rX1.rect.x2;

                rX2.clear(set);
                rX2.area = rX2.rect.x1;

                int res = solve(set);
                if (res < n) return -1_000_000;
                result += res;
                continue;
            } else {
                rY1.area = Math.max(rY1.area, rY1.rect.y2);
            }

            rY2.next();
            if (rY2.rect.y2 <= rY2.area) {
                int n = rY2.i - 1;
                Set<Rect> set = rY2.drain();
                rY2.area = rY2.rect.y1;

                rY1.clear(set);
                rY1.area = rY1.rect.y2;

                rX1.clear(set);
                rX1.area = rX1.rect.x2;

                rX2.clear(set);
                rX2.area = rX2.rect.x1;

                int res = solve(set);
                if (res < n) return -1_000_000;
                result += res;
                continue;
            } else {
                rY2.area = Math.min(rY2.area, rY2.rect.y1);
            }
        }
        if (result == 0) {
            return 0;
        } else {
            return result + solve(setX1);
        }
    }

//********************************************************************************************
//********************************************************************************************
//********************************************************************************************

    static class SolutionFailedException extends Exception {
        int code;

        public SolutionFailedException(int code) {
            this.code = code;
        }
    }

    private static void shuffle(int[] array) {
        Random random = new Random();
        for (int i = array.length - 1; i > 0; i--) {
            int index = random.nextInt(i + 1);
            int temp = array[index];
            array[index] = array[i];
            array[i] = temp;
        }
    }

    /**
     * If searched element doesn't exist, returns index of first element which is bigger than searched value.

     * If searched element is bigger than any array element function returns first index after last element.

     * If searched element is lower than any array element function returns index of first element.

     * If there are many values equals searched value function returns first occurrence.

     */
    private static int lowerBound(long[] arr, long key) {
        int lo = 0;
        int hi = arr.length - 1;
        while (lo < hi) {
            int mid = (lo + hi) / 2;
            if (key <= arr[mid]) {
                hi = mid - 1;
            } else {
                lo = mid + 1;
            }
        }
        return arr[lo] < key ? lo + 1 : lo;
    }

    /**
     * Returns index of first element which is grater than searched value.
     * If searched element is bigger than any array element, returns first index after last element.
     */
    private static int upperBound(long[] arr, long key) {
        int lo = 0;
        int hi = arr.length - 1;
        while (lo < hi) {
            int mid = (lo + hi) / 2;
            if (key >= arr[mid]) {
                lo = mid + 1;
            } else {
                hi = mid;
            }
        }
        return arr[lo] <= key ? lo + 1 : lo;
    }

    private static int ceil(double d) {
        int ret = (int) d;
        return ret == d ? ret : ret + 1;
    }

    private static int round(double d) {
        return (int) (d + 0.5);
    }

    private static int gcd(int a, int b) {
        BigInteger b1 = BigInteger.valueOf(a);
        BigInteger b2 = BigInteger.valueOf(b);
        BigInteger gcd = b1.gcd(b2);
        return gcd.intValue();
    }

    private static long gcd(long a, long b) {
        BigInteger b1 = BigInteger.valueOf(a);
        BigInteger b2 = BigInteger.valueOf(b);
        BigInteger gcd = b1.gcd(b2);
        return gcd.longValue();
    }

    private int[] readIntArray(int n) {
        int[] res = new int[n];
        for (int i = 0; i < n; i++) {
            res[i] = sc.nextInt();
        }
        return res;
    }

    private long[] readLongArray(int n) {
        long[] res = new long[n];
        for (int i = 0; i < n; i++) {
            res[i] = sc.nextLong();
        }
        return res;
    }

    @SuppressWarnings("unused")
    static class FastScanner {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;

        FastScanner(InputStream stream) {
            this.stream = stream;
        }

        int read() {
            if (numChars == -1)
                throw new InputMismatchException();
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0) return -1;
            }
            return buf[curChar++];
        }

        boolean isSpaceChar(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        boolean isEndline(int c) {
            return c == '\n' || c == '\r' || c == -1;
        }

        public int nextInt() {
            return Integer.parseInt(next());
        }

        public long nextLong() {
            return Long.parseLong(next());
        }

        public double nextDouble() {
            return Double.parseDouble(next());
        }

        public String next() {
            int c = read();
            while (isSpaceChar(c)) c = read();
            StringBuilder res = new StringBuilder();
            do {
                res.appendCodePoint(c);
                c = read();
            } while (!isSpaceChar(c));
            return res.toString();
        }

        public String nextLine() {
            int c = read();
            while (isEndline(c))
                c = read();
            StringBuilder res = new StringBuilder();
            do {
                res.appendCodePoint(c);
                c = read();
            } while (!isEndline(c));
            return res.toString();
        }

    }

    private boolean oj = System.getProperty("ONLINE_JUDGE") != null;

    private void tr(Object... o) {
        if (!oj) System.out.println(Arrays.deepToString(o));
    }
}