Read problems statements in Mandarin Chinese, Russian and Vietnamese as well. 

Chef is an advocate for Go Green Initiative. Today he had n trees planted in a row outside his his restaurant. Today, the height of i-th tree is h_{i} feet. The trees grow at a rate of m_{i} feet per day.

Chef knows that trees will look beautiful if they form a zig-zag sequence. The trees will be said to be in Zig-zag sequence if the heights of tree first increases or decreases, then alternates between decreasing/increasing respectively. Formally, the trees will be said to in Zig-zag sequence if one of the following two conditions holds.

h_{1} < h_{2} > h_{3} < h_{4} and so on..
h_{1} >  h_{2} < h_{3} > h_{4} and so on..

Chef wants to know intervals of time when the heights of the trees will form a zig-zag sequence.

------ Input ------ 

The first line of the input contains an integer T denoting the number of test cases. The description of T test cases follows.

The first line of each test case contains a single integer n, denoting the number of trees.

The i^{th} of following N lines contains two space separated integers h_{i} and m_{i}, denoting the initial height and the growth speed for i^{th} tree.
 
------ Output ------ 

For each test case, output an integer Q - the amount of the periods of consecutive moments of time, when the trees for a zig-zag sequence.
On the following Q lines, output the intervals of time when the trees' heights form a zig-zag sequence. For each intervals, output its' smallest and the largest instants of time. If the range is infinite, output Inf as the right bound.
The test cases are designed in such a way that the total output won't exceed 2 MB.

------ Constraints ------ 

$1 ≤ T ≤ 10^{5}$
$1 ≤ n ≤ 10$

$Subtask 1 (23 points): 0 ≤ h_{i}, m_{i} ≤ 10$

$Subtask 2 (77 points): 0 ≤ h_{i}, m_{i} ≤ 10^{9}$

$1 ≤ sum of n over a test cases in a single test file ≤ 5 × 10^{5}$

------ Example ------ 

Input:
3
3
0 1
2 2
0 3
2
2 1
1 2
3
1 1
2 2
3 3

Output:
1
0 1
2
0 0
2 Inf
0

------ Explanation ------ 

Example case 1. In the first case 0 2 0 is already a zig-zag sequence, but on the 2nd second it will become 2 6 6 and will never turn back into zig-zag

Difficulty: HARD
Tags: Constructive algorithms

Ad-hoc

Starter code:

Solutions:
import math

def next_int(n):
	if int(n) == n:
		return int(n + 1)
	return int(math.ceil(n))

def prev_int(n):
	if int(n) == n:
		return int(n - 1)
	return int(math.floor(n))

def get_ranges(h1, s1, h2, s2):
	infinity = float('inf')
	if h1 == h2 and s1 == s2:
		return tuple()
	if h1 == h2:
		return (('<' if s1 < s2 else '>', 1, infinity),)
	initial_relation = '<' if h1 < h2 else '>'
	if s1 == s2:
		return ((initial_relation, 0, infinity),)
	intersect = (h2 - h1) / (s1 - s2)
	if intersect < 0:
		return ((initial_relation, 0, infinity),)
	reversed_relation = '>' if initial_relation == '<' else '<'
	return ((initial_relation, 0, prev_int(intersect)), (reversed_relation, next_int(intersect), infinity))

def intersect_ranges(range1, range2):
	if range1[0] > range2[1] or range2[0] > range1[1]:
		return None
	return (max(range1[0], range2[0]), min(range1[1], range2[1]))

def merge_adjacent_ranges(ranges):
	if len(ranges) == 0:
		return []
	temp = [list(ranges[0])]
	for i in range(1, len(ranges)):
		if temp[-1][1] + 1 == ranges[i][0]:
			temp[-1][1] = ranges[i][1]
		else:
			temp.append(ranges[i])
	return temp

def get_zig_zag_ranges(ranges1, ranges2):
	if len(ranges1) == 0 or len(ranges2) == 0:
		return tuple()
	result = []
	for r1 in ranges1:
		for r2 in ranges2:
			if r1[0] != r2[0]:
				intersection = intersect_ranges((r1[1], r1[2]), (r2[1], r2[2]))
				if intersection:
					result.append(intersection)
	return tuple(result)

def read_and_run_test():
	tree_count = int(input())
	trees = list()
	for i in range(tree_count):
		trees.append([int(v) for v in input().split()])
	if tree_count == 1:
		print('1\n0 Inf')
		return
	infinity = float('inf')
	prev_ranges = get_ranges(trees[0][0], trees[0][1], trees[1][0], trees[1][1])
	results = [(s, e) for (r, s, e) in prev_ranges]
	for i in range(2, tree_count):
		curr_ranges = get_ranges(trees[i - 1][0], trees[i - 1][1], trees[i][0], trees[i][1])
		new_results = []
		for new_range in get_zig_zag_ranges(prev_ranges, curr_ranges):
			for existing_range in results:
				intersection = intersect_ranges(new_range, existing_range)
				if intersection:
					new_results.append(intersection)
		results = new_results
		prev_ranges = curr_ranges
	results = merge_adjacent_ranges(results)
	print(len(results))
	for r in results:
		if r[1] == infinity:
			print(int(r[0]), 'Inf')
		else:
			print(int(r[0]), int(r[1]))

def main():
	test_cases_count = int(input())
	for i in range(test_cases_count):
		read_and_run_test()
main()


def intersect(iv1, iv2):
	(b1, e1) = iv1
	(b2, e2) = iv2
	if b1 < 0 or b2 < 0:
		return (-1, 0)
	b = max(b1, b2)
	if e1 < 0 or e2 < 0:
		e = max(e1, e2)
	else:
		e = min(e1, e2)
	if e < 0 or b <= e:
		return (b, e)
	else:
		return (-1, 0)

def plus(h, m, hi, mi):
	if m == mi:
		if h < hi:
			return (0, -1)
		else:
			return (-1, 0)
	tz = (hi - h) // (m - mi)
	tu = tz + 1
	if (m - mi) * tz == hi - h:
		td = tz - 1
	else:
		td = tz
	if td < 0:
		d = (-1, 0)
	else:
		d = (0, td)
	if tu < 0:
		u = (0, -1)
	else:
		u = (tu, -1)
	if m < mi:
		return u
	else:
		return d

def minus(h, m, hi, mi):
	if m == mi:
		if h > hi:
			return (0, -1)
		else:
			return (-1, 0)
	tz = (hi - h) // (m - mi)
	tu = tz + 1
	if (m - mi) * tz == hi - h:
		td = tz - 1
	else:
		td = tz
	if td < 0:
		d = (-1, 0)
	else:
		d = (0, td)
	if tu < 0:
		u = (0, -1)
	else:
		u = (tu, -1)
	if m > mi:
		return u
	else:
		return d

def prt(iv):
	(b, e) = iv
	if b >= 0:
		print(b, end=' ')
		if e >= 0:
			print(e)
		else:
			print('Inf')
T = int(input())
for t in range(T):
	N = int(input())
	pp = (0, -1)
	mm = (0, -1)
	for i in range(N):
		(hi, mi) = map(int, input().split())
		if i:
			pp = intersect(pp, plus(h, m, hi, mi))
			mm = intersect(mm, minus(h, m, hi, mi))
			(pp, mm) = (mm, pp)
		(h, m) = (hi, mi)
	if pp > mm:
		(pp, mm) = (mm, pp)
	if pp == mm:
		mm = (-1, 0)
	if pp[0] >= 0 and pp[1] + 1 == mm[0]:
		pp = (pp[0], mm[1])
		mm = (-1, 0)
	if N < 0:
		pp = (-1, 0)
		mm = (-1, 0)
	print((pp[0] >= 0) + (mm[0] >= 0))
	prt(pp)
	prt(mm)


import math
t = int(input())
for _ in range(t):
	n = int(input())
	h = [0] * n
	m = [0] * n
	for i in range(n):
		(h[i], m[i]) = map(int, input().split())
	l1 = [0] * (n - 1)
	r1 = [10 ** 10] * (n - 1)
	l2 = [0] * (n - 1)
	r2 = [10 ** 10] * (n - 1)
	l1max = 0
	l2max = 0
	r1min = 10 ** 10
	r2min = 10 ** 10
	flag1 = 0
	flag2 = 0
	for i in range(n - 1):
		mdif = m[i + 1] - m[i]
		hdif = h[i] - h[i + 1]
		if i % 2 == 0:
			if mdif != 0:
				x = hdif / mdif
				if mdif > 0:
					if x < 0:
						x = 0
					else:
						x = int(x + 1)
					l1[i] = x
					if l1max < l1[i]:
						l1max = l1[i]
				else:
					if x <= 0:
						r1[i] = -100
						r1min = -100
						break
					elif math.ceil(x) == math.floor(x):
						x = int(x - 1)
					else:
						x = int(x)
					r1[i] = x
					if r1min > r1[i]:
						r1min = r1[i]
			if mdif == 0:
				if h[i] >= h[i + 1]:
					l1[i] = 10 ** 10 + 10
					l1max = 10 ** 10 + 10
					break
		else:
			if mdif != 0:
				x = hdif / mdif
				if mdif > 0:
					if x <= 0:
						r1[i] = -100
						r1min = -100
						break
					elif math.ceil(x) == math.floor(x):
						x = int(x - 1)
					else:
						x = int(x)
					r1[i] = x
					if r1min > r1[i]:
						r1min = r1[i]
				else:
					if x < 0:
						x = 0
					else:
						x = int(x + 1)
					l1[i] = x
					if l1max < l1[i]:
						l1max = l1[i]
			if mdif == 0:
				if h[i] <= h[i + 1]:
					l1[i] = 10 ** 10 + 10
					l1max = 10 ** 10 + 10
					break
	for i in range(n - 1):
		mdif = m[i + 1] - m[i]
		hdif = h[i] - h[i + 1]
		if i % 2 == 0:
			if mdif != 0:
				x = hdif / mdif
				if mdif > 0:
					if x <= 0:
						r2[i] = -100
						r2min = -100
						break
					elif math.ceil(x) == math.floor(x):
						x = int(x - 1)
					else:
						x = int(x)
					r2[i] = x
					if r2min > r2[i]:
						r2min = r2[i]
				else:
					if x < 0:
						x = 0
					else:
						x = int(x + 1)
					l2[i] = x
					if l2max < l2[i]:
						l2max = l2[i]
			if mdif == 0:
				if h[i] <= h[i + 1]:
					l2[i] = 10 ** 10 + 10
					l2max = 10 ** 10 + 10
					break
		else:
			if mdif != 0:
				x = hdif / mdif
				if mdif > 0:
					if x < 0:
						x = 0
					else:
						x = int(x + 1)
					l2[i] = x
					if l2max < l2[i]:
						l2max = l2[i]
				else:
					if x <= 0:
						r2[i] = -100
						r2min = -100
						break
					elif math.ceil(x) == math.floor(x):
						x = int(x - 1)
					else:
						x = int(x)
					r2[i] = x
					if r2min > r2[i]:
						r2min = r2[i]
			if mdif == 0:
				if h[i] >= h[i + 1]:
					l2[i] = 10 ** 10 + 10
					l2max = 10 ** 10 + 10
					break
	ans = 0
	if l1max <= r1min:
		flag1 = 1
		ans = 1
	if l2max <= r2min:
		flag2 = 1
		ans = 1
	if flag1 == 1 and flag2 == 1:
		if l1max - r2min > 1 or (l2max - r1min > 1 and l1max != l2max):
			ans = 2
		else:
			ans = 1
			l1max = min(l1max, l2max)
			r1min = max(r1min, r2min)
			flag2 = 0
	print(ans)
	if flag1 == 1 and ans == 1:
		if r1min >= 10 ** 10:
			r1min = 'Inf'
		print(l1max, r1min)
	if flag2 == 1 and ans == 1:
		if r2min >= 10 ** 10:
			r2min = 'Inf'
		print(l2max, r2min)
	if ans == 2:
		if r2min >= 10 ** 10:
			r2min = 'Inf'
		if r1min >= 10 ** 10:
			r1min = 'Inf'
		if l1max < l2max:
			print(l1max, r1min)
			print(l2max, r2min)
		elif l2max < l1max:
			print(l2max, r2min)
			print(l1max, r1min)


def getInterval(x, y):
	a = y[0] - x[0]
	d = y[1] - x[1]
	if a <= 0 and d <= 0:
		return None
	if a > 0 and d >= 0:
		return (0, None)
	t = int(-a / d) + 1
	if abs(a) % abs(d) == 0:
		t = abs(a) // abs(d)
		if a <= 0:
			t += 1
	if a > 0:
		return (0, t - 1)
	return (t, None)

def inter(a, b):
	if a is None or b is None:
		return None
	x = max(a[0], b[0])
	y = a[1]
	if a[1] is None:
		y = b[1]
	elif b[1] is None:
		y = a[1]
	else:
		y = min(a[1], b[1])
	if y is not None and y < x:
		return None
	return (x, y)

def pstr(a, b):
	ret = str(a) + ' ' + ('Inf' if b is None else str(b))
	return ret

def solve(x):
	if len(x) == 1:
		print(1)
		print('0 Inf')
		return
	up = (0, None)
	dn = (0, None)
	for i in range(len(x) - 1):
		if i % 2 == 0:
			dn = inter(dn, getInterval(x[i], x[i + 1]))
			up = inter(up, getInterval(x[i + 1], x[i]))
		else:
			up = inter(up, getInterval(x[i], x[i + 1]))
			dn = inter(dn, getInterval(x[i + 1], x[i]))
	ret = 0
	if up is not None:
		ret += 1
	if dn is not None:
		ret += 1
	if up is not None and dn is not None:
		if up[0] > dn[0]:
			(up, dn) = (dn, up)
		if up[1] == dn[0] - 1:
			up = (up[0], dn[1])
			dn = None
			ret -= 1
	print(ret)
	if up is not None:
		print(pstr(*up))
	if dn is not None:
		print(pstr(*dn))
import sys
f = sys.stdin
t = int(f.readline())
for i in range(t):
	n = int(f.readline())
	x = []
	for j in range(n):
		(a, b) = map(int, f.readline().split())
		x += [(a, b)]
	solve(x)


import math

def test(Inf):
	(Min_1, Min_0) = (-1, -1)
	(Max_1, Max_0) = (Inf, Inf)
	N = int(input().strip())
	(H_0, M_0) = map(int, input().strip().split(' '))
	for i in range(1, N):
		(H_1, M_1) = map(int, input().strip().split(' '))
		(H, M) = (H_1 - H_0, M_0 - M_1)
		(H_0, M_0) = (H_1, M_1)
		if i & 1:
			if M == 0:
				if H == 0:
					Max_1 = -1
					Max_0 = -1
				if H > 0:
					Max_1 = -1
				if H < 0:
					Max_0 = -1
			if M > 0:
				Min_1 = max(Min_1, H / M)
				Max_0 = min(Max_0, H / M)
			if M < 0:
				Min_0 = max(Min_0, H / M)
				Max_1 = min(Max_1, H / M)
		else:
			if M == 0:
				if H == 0:
					Max_1 = -1
					Max_0 = -1
				if H > 0:
					Max_0 = -1
				if H < 0:
					Max_1 = -1
			if M > 0:
				Min_0 = max(Min_0, H / M)
				Max_1 = min(Max_1, H / M)
			if M < 0:
				Min_1 = max(Min_1, H / M)
				Max_0 = min(Max_0, H / M)
	if Max_0 < Inf:
		Max_0 = math.ceil(Max_0) - 1
	if Max_1 < Inf:
		Max_1 = math.ceil(Max_1) - 1
	Min_0 = math.floor(Min_0) + 1
	Min_1 = math.floor(Min_1) + 1
	if Min_0 <= Max_0 and Min_1 <= Max_1:
		if max(Min_0, Min_1) <= min(Max_0, Max_1) + 1:
			print(1)
			print(str(min(Min_0, Min_1)) + ' ' + str(max(Max_0, Max_1)).capitalize())
		else:
			print(2)
			print(str(min(Min_0, Min_1)) + ' ' + str(min(Max_0, Max_1)))
			print(str(max(Min_0, Min_1)) + ' ' + str(max(Max_0, Max_1)).capitalize())
	elif Min_0 <= Max_0:
		print(1)
		print(str(Min_0) + ' ' + str(Max_0).capitalize())
	elif Min_1 <= Max_1:
		print(1)
		print(str(Min_1) + ' ' + str(Max_1).capitalize())
	else:
		print(0)
	return
T = int(input().strip())
Inf = float('inf')
for i in range(T):
	test(Inf)


from math import floor, ceil
inf = 10 ** 20
for t in range(int(input())):
	h = []
	m = []
	n = int(input())
	for i in range(n):
		(hi, mi) = [int(i) for i in input().split()]
		h.append(hi)
		m.append(mi)
	if n == 1:
		print(1)
		print(0, 'Inf')
		continue
	lowhigh = []
	highlow = []
	for i in range(1, n):
		if h[i] > h[i - 1] and m[i] >= m[i - 1]:
			lowhigh.append((0, inf))
		elif h[i] > h[i - 1] and m[i] < m[i - 1]:
			top = ceil((h[i] - h[i - 1]) / (m[i - 1] - m[i])) - 1
			lowhigh.append((0, top))
		elif m[i] > m[i - 1]:
			low = floor((h[i] - h[i - 1]) / (m[i - 1] - m[i])) + 1
			lowhigh.append((low, inf))
		else:
			lowhigh.append((0, -1))
		if h[i] < h[i - 1] and m[i] <= m[i - 1]:
			highlow.append((0, inf))
		elif h[i] < h[i - 1] and m[i] > m[i - 1]:
			top = ceil((h[i - 1] - h[i]) / (m[i] - m[i - 1])) - 1
			highlow.append((0, top))
		elif m[i] < m[i - 1]:
			low = floor((h[i - 1] - h[i]) / (m[i] - m[i - 1])) + 1
			highlow.append((low, inf))
		else:
			highlow.append((0, -1))
	for i in range(1, n - 1, 2):
		(lowhigh[i], highlow[i]) = (highlow[i], lowhigh[i])
	mn1 = max(lowhigh, key=lambda i: i[0])[0]
	mx1 = min(lowhigh, key=lambda i: i[1])[1]
	lowhigh = True if mn1 <= mx1 else False
	mx1 = 'Inf' if mx1 == inf else mx1
	mn2 = max(highlow, key=lambda i: i[0])[0]
	mx2 = min(highlow, key=lambda i: i[1])[1]
	highlow = True if mn2 <= mx2 else False
	mx2 = 'Inf' if mx2 == inf else mx2
	if not (lowhigh or highlow):
		print(0)
	elif lowhigh and highlow:
		if type(mx2) == int and mn1 == mx2 + 1 or (type(mx1) == int and mn2 == mx1 + 1):
			print(1)
			print(0, 'Inf')
		else:
			print(2)
			if mn1 < mn2:
				print(mn1, mx1)
				print(mn2, mx2)
			else:
				print(mn2, mx2)
				print(mn1, mx1)
	elif lowhigh:
		print(1)
		print(mn1, mx1)
	else:
		print(1)
		print(mn2, mx2)