Problem:
Score : 700 points

Problem Statement

We have a rooted binary tree with N vertices, where the vertices are numbered 1 to N.
Vertex 1 is the root, and the parent of Vertex i (i \geq 2) is Vertex \left[ \frac{i}{2} \right].

Each vertex has one item in it. The item in Vertex i has a value of V_i and a weight of W_i.
Now, process the following query Q times:

Given are a vertex v of the tree and a positive integer L.
Let us choose some (possibly none) of the items in v and the ancestors of v so that their total weight is at most L.
Find the maximum possible total value of the chosen items.

Here, Vertex u is said to be an ancestor of Vertex v when u is an indirect parent of v, that is, there exists a sequence of vertices w_1,w_2,\ldots,w_k (k\geq 2) where w_1=v, w_k=u, and w_{i+1} is the parent of w_i for each i.

Constraints

All values in input are integers.

1 \leq N < 2^{18}

1 \leq Q \leq 10^5

1 \leq V_i \leq 10^5

1 \leq W_i \leq 10^5

For the values v and L given in each query, 1 \leq v \leq N and 1 \leq L \leq 10^5.

Input

Let v_i and L_i be the values v and L given in the i-th query.
Then, Input is given from Standard Input in the following format:

N
V_1 W_1
:
V_N W_N
Q
v_1 L_1
:
v_Q L_Q

Output

For each integer i from 1 through Q,
the i-th line should contain the response to the i-th query.

Sample Input 1

3
1 2
2 3
3 4
3
1 1
2 5
3 5

Sample Output 1

0
3
3

In the first query, we are given only one choice: the item with (V, W)=(1,2). Since L = 1, we cannot actually choose it, so our response should be 0.

In the second query, we are given two choices: the items with (V, W)=(1,2) and (V, W)=(2,3). Since L = 5, we can choose both of them, so our response should be 3.

Sample Input 2

15
123 119
129 120
132 112
126 109
118 103
115 109
102 100
130 120
105 105
132 115
104 102
107 107
127 116
121 104
121 115
8
8 234
9 244
10 226
11 227
12 240
13 237
14 206
15 227

Sample Output 2

256
255
250
247
255
259
223
253

Solution in C# (.NET Core 3.1.201) (judge verdict: Accepted)

#nullable enable
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Numerics;
using System.Threading.Tasks;
using static System.Console;
using static System.Math;
using static Func;
using System.Threading;
using System.ComponentModel.Design.Serialization;
using System.Diagnostics.CodeAnalysis;

class Z { static void Main() => new K(); }
class K
{
	int F => int.Parse(Str);
	long FL => long.Parse(Str);
	int[] G => Strs.Select(int.Parse).ToArray();
	uint[] GU => Strs.Select(uint.Parse).ToArray();
	decimal[] GD => Strs.Select(decimal.Parse).ToArray();
	long[] GL => Strs.Select(long.Parse).ToArray();
	string Str => ReadLine();
	string[] Strs => Str.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
	static ulong One(int k) => 1ul << k;
	static ulong All(int k) => One(k) - 1;
	static bool Has(ulong s, int k) => (s & One(k)) != 0;
	const int MOD = 1000000007;
	public K()
	{
		SetOut(new StreamWriter(OpenStandardOutput()) { AutoFlush = false });
		var t = new Thread(Solve, 0);
		t.Start();
		t.Join();
		Out.Flush();
	}
	void Solve()
	{
		var N = F;
		var items = new Item[N];
		for (var i = 0; i < N; i++)
		{
			var I = G;
			items[i] = new Item(I[0], I[1]);
		}
		var Q = F;
		var qs = new Query[Q];
		for (var q = 0; q < Q; q++)
		{
			var I = G;
			qs[q] = new Query(I[0] - 1, I[1]);
		}
		var L_MAX = qs.Max(q => q.Weight);
		var memo = new List<Item>[1 << 12];
		memo[0] = new List<Item> { new Item() };
		if (items[0].Weight <= L_MAX) memo[0].Add(new Item(items[0].Value, items[0].Weight));
		var UB = Min(memo.Length, N);
		for (var i = 1; i < UB; ++i)
		{
			var x = items[i];
			var p = (i + 1) / 2 - 1;
			memo[i] = new List<Item>(memo[p].Count * 2);
			memo[i].AddRange(memo[p]);
			foreach (var y in memo[p]) memo[i].Add(x + y);
			Normalize(memo[i]);
		}
		foreach (var q in qs)
		{
			var i = q.Index;
			var idx = new List<int>(6);
			while (i >= memo.Length)
			{
				idx.Add(i);
				i = (i + 1) / 2 - 1;
			}
			var best = 0;
			var ALL = (1u << idx.Count()) - 1u;
			for (var s = 0u; s <= ALL; ++s)
			{
				var item = new Item();
				for (var j = 0; j < idx.Count; ++j)
					if (Has(s, j)) item += items[idx[j]];
				if (item.Weight > q.Weight) continue;
				int min = 0, max = memo[i].Count, T = q.Weight - item.Weight;
				while (min < max)
				{
					var mid = (min + max) / 2;
					if (memo[i][mid].Weight > T) max = mid;
					else min = mid + 1;
				}
				Chmax(ref best, memo[i][min - 1].Value + item.Value);
			}
			WriteLine(best);
		}
	}
	void Normalize(List<Item> t)
	{
		t.Sort();
		int i = 0, j = 0, best = -1;
		while (i < t.Count)
			if (t[i].Value > best)
			{
				best = t[i].Value;
				t.Swap(i++, j++);
			}
			else i++;
		t.RemoveRange(j, t.Count - j);
	}
}
struct Item : IComparable<Item>
{
	public readonly int Value, Weight;
	public Item(int v, int w) { Value = v; Weight = w; }
	public override string ToString() => $"Item(v={Value}, w={Weight})";
	public int CompareTo(Item other) => Weight.CompareTo(other.Weight);
	public static Item operator +(Item a, Item b) => new Item(a.Value + b.Value, a.Weight + b.Weight);
}
struct Query : IComparable<Query>
{
	public readonly int Index, Weight;
	public Query(int i, int w) { Index = i; Weight = w; }
	public override string ToString() => $"Query(i={Index}, w={Weight})";
	public int CompareTo(Query other) => Weight.CompareTo(other.Weight);
}
static class Func
{
	public const int Inf = 1073741789;
	public const long InfL = 4011686018427387913L;
	public static T[] ConstantArray<T>(int n, T val) { var a = new T[n]; for (var i = 0; i < n; i++) a[i] = val; return a; }
	public static T[,] ConstantArray<T>(int n, int m, T val) { var a = new T[n, m]; for (var i = 0; i < n; i++) for (var j = 0; j < m; j++) a[i, j] = val; return a; }
	public static T[,,] ConstantArray<T>(int n, int m, int l, T val) { var a = new T[n, m, l]; for (var i = 0; i < n; i++) for (var j = 0; j < m; j++) for (var k = 0; k < l; k++) a[i, j, k] = val; return a; }
	public static T[] MakeArray<T>(int n, Func<int, T> f) { var a = new T[n]; for (var i = 0; i < n; i++) a[i] = f(i); return a; }
	public static T[,] MakeArray<T>(int n, int m, Func<int, int, T> f) { var a = new T[n, m]; for (var i = 0; i < n; i++) for (var j = 0; j < m; j++) a[i, j] = f(i, j); return a; }
	public static T[,,] MakeArray<T>(int n, int m, int l, Func<int, int, int, T> f) { var a = new T[n, m, l]; for (var i = 0; i < n; i++) for (var j = 0; j < m; j++) for (var k = 0; k < l; k++) a[i, j, k] = f(i, j, k); return a; }
	public static T[] Recurse<T>(int n, T a0, Func<int, T, T> f) { var a = new T[n]; a[0] = a0; for (var i = 1; i < n; i++) a[i] = f(i, a[i - 1]); return a; }
	public static T[] Accumulate<T>(IList<T> a, T zero, Func<T, T, T> f) { var s = new T[a.Count + 1]; s[0] = zero; for (var i = 0; i < a.Count; i++) s[i + 1] = f(s[i], a[i]); return s; }
	public static int FirstBinary(int min, int max, Predicate<int> pred)
	{
		while (min < max)
		{
			var mid = (min + max) / 2;
			if (pred(mid)) max = mid;
			else min = mid + 1;
		}
		return min;
	}
	public static long GCD(long a, long b)
	{
		var n = (ulong)Abs(a); var m = (ulong)Abs(b);
		if (n == 0) return (long)m; if (m == 0) return (long)n;
		int zm = 0, zn = 0;
		while ((n & 1) == 0) { n >>= 1; zn++; }
		while ((m & 1) == 0) { m >>= 1; zm++; }
		while (m != n)
			if (m > n) { m -= n; while ((m & 1) == 0) m >>= 1; }
			else { n -= m; while ((n & 1) == 0) n >>= 1; }
		return (long)n << Math.Min(zm, zn);
	}
	public static long Mod(long a, long mod) => (a % mod + mod) % mod;
	public static long Inverse(long a, long mod) => Mod(SolveLinear(Mod(a, mod), mod).x, mod);
	public static long Pow(long a, long b)
	{
		var p = 1L;
		var x = a;
		while (b > 0)
		{
			if ((b & 1) == 1) p *= x;
			b >>= 1;
			x *= x;
		}
		return p;
	}
	public static long Pow(long a, long b, long mod)
	{
		var p = 1L;
		var x = a;
		while (b > 0)
		{
			if ((b & 1) == 1) p = p * x % mod;
			b >>= 1;
			x = x * x % mod;
		}
		return p;
	}
	public static ulong Pow(ulong a, ulong b, ulong mod)
	{
		var p = 1uL;
		var x = a;
		while (b > 0)
		{
			if ((b & 1) == 1) p = p * x % mod;
			b >>= 1;
			x = x * x % mod;
		}
		return p;
	}
	// return (x, y) such that n * x + m * y == gcd(n, m)
	public static (long x, long y) SolveLinear(long n, long m)
	{
		var A = new long[,] { { n < 0 ? -1 : 1, 0 }, { 0, m < 0 ? -1 : 1 } };
		n = Abs(n); m = Abs(m);
		while (m > 0)
		{
			long q = n / m, r = n % m;
			(n, m) = (m, r);
			for (var i = 0; i < 2; i++) (A[i, 0], A[i, 1]) = (A[i, 1], A[i, 0] - q * A[i, 1]);
		}
		return (A[0, 0], A[1, 0]);
	}
	public static int CombineHashCodes(int h1, int h2) => ((h1 << 5) + h1) ^ h2;
	public static int[] GetFact(int lim, int mod)
	{
		var f = new int[lim];
		f[0] = 1;
		for (var i = 1; i < lim; i++) f[i] = (int)((long)f[i - 1] * i % mod);
		return f;
	}
	public static int[] GetInvFact(int lim, int mod)
	{
		var fc = 1;
		for (var i = 2; i < lim; i++) fc = (int)((long)fc * i % mod);
		return GetInvFact(lim, fc, mod);
	}
	// GetInvFact(n, (n-1)! mod p, p) gives {1, 1/2, ..., 1/(n-1)!} mod p
	public static int[] GetInvFact(int lim, int fc_of_lim_m_1, int mod)
	{
		var ifc = new int[lim];
		ifc[lim - 1] = (int)Inverse(fc_of_lim_m_1, mod);
		for (var i = lim - 1; i >= 1; i--) ifc[i - 1] = (int)((long)ifc[i] * i % mod);
		return ifc;
	}
	public static Comparison<T> DefaultComparison<T>() => (x, y) => Comparer<T>.Default.Compare(x, y);
	public static Comparison<T> ToComparison<T>(this IComparer<T>? comp) => comp switch { null => DefaultComparison<T>(), _ => (x, y) => comp.Compare(x, y) };
	public static bool Chmax<T>(ref T a, T b) where T : IComparable<T>
	{
		if (a.CompareTo(b) < 0)
		{
			a = b;
			return true;
		}
		return false;
	}
	public static bool Chmin<T>(ref T a, T b) where T : IComparable<T>
	{
		if (a.CompareTo(b) > 0)
		{
			a = b;
			return true;
		}
		return false;
	}
	public static void Swap<T>(this IList<T> array, int i, int j) => (array[i], array[j]) = (array[j], array[i]);
	public static void Swap<T>(ref T a, ref T b) => (a, b) = (b, a);
	public static void Shuffle<T>(IList<T> source, Random rand) { for (var i = source.Count - 1; i >= 0; --i) source.Swap(i, rand.Next(0, i + 1)); }
	public static double Min(params double[] nums) { var min = double.MaxValue; foreach (var n in nums) min = Math.Min(min, n); return min; }
	// get all primes less than or equal to n
	public static List<int> GetPrimes(int n)
	{
		if (n < 3) n = 3;
		var m = (n - 1) >> 1;
		var ps = new List<int>((int)(n / Log(n))) { 2 };
		var ng = new bool[m];
		for (var i = 0; i < m; i++)
			if (!ng[i])
			{
				var p = 2 * i + 3;
				ps.Add(p);
				for (var k = 3 * i + 3; k < m; k += p) ng[k] = true;
			}
		return ps;
	}
	public static long ChineseRemainder((long mod, long rem) mr1, (long mod, long rem) mr2)
	{
		var (m1, r1) = mr1;
		var (m2, r2) = mr2;
		var (x, y) = SolveLinear(m1, m2);
		return (m1 * x * r2 + m2 * y * r1) % (m1 * m2);
	}
	public static long ChineseRemainder(params (long mod, long rem)[] mrs)
	{
		if (mrs.Length == 0) return 0;
		if (mrs.Length == 1) return mrs[0].rem;
		if (mrs.Length == 2) return ChineseRemainder(mrs[0], mrs[1]);
		(long mod, long rem) t = (1, 0);
		for (var i = 0; i < mrs.Length; i++) t = (t.mod * mrs[i].mod, ChineseRemainder(t, mrs[i]));
		return t.rem;
	}
	public static bool IsPrime(ulong n)
	{
		if (n <= 1 || (n > 2 && n % 2 == 0)) return false;
		var test = new uint[] { 2, 3, 5, 7, 11, 13, 17, 19, 23, 111 };
		var d = n - 1;
		var s = 0;
		while (d % 2 == 0) { ++s; d /= 2; }
		bool f(ulong t)
		{
			var x = Pow(t, d, n);
			if (x == 1) return true;
			for (var r = 0L; r < s; r++)
			{
				if (x == n - 1) return true;
				x = x * x % n;
			}
			return false;
		};
		for (var i = 0; test[i] < n && test[i] != 111; i++) if (!f(test[i])) return false;
		return true;
	}
}
class PriorityQueue<T> : IEnumerable<T>, ICollection, IEnumerable, ICloneable
{
	readonly Comparison<T> comp;
	List<T> list;
	public int Count { get; private set; } = 0;
	public bool IsEmpty => Count == 0;
	public PriorityQueue(IEnumerable<T> source) : this((Comparison<T>?)null, 0, source) { }
	public PriorityQueue(int capacity = 4, IEnumerable<T>? source = null) : this((Comparison<T>?)null, capacity, source) { }
	public PriorityQueue(IComparer<T> comp, IEnumerable<T>? source) : this(comp.ToComparison(), source) { }
	public PriorityQueue(IComparer<T> comp, int capacity = 4, IEnumerable<T>? source = null) : this(comp.ToComparison(), source) => list.Capacity = capacity;
	public PriorityQueue(Comparison<T>? comp, IEnumerable<T>? source) : this(comp, 0, source) { }
	public PriorityQueue(Comparison<T>? comp, int capacity = 4, IEnumerable<T>? source = null) { this.comp = comp ?? DefaultComparison<T>(); list = new List<T>(capacity); if (source != null) foreach (var x in source) Enqueue(x); }
	/// <summary>
	/// add an item
	/// this is an O(log n) operation
	/// </summary>
	/// <param name="x">item</param>
	public void Enqueue(T x)
	{
		var pos = Count++;
		list.Add(x);
		while (pos > 0)
		{
			var p = (pos - 1) / 2;
			if (comp(list[p], x) <= 0) break;
			list[pos] = list[p];
			pos = p;
		}
		list[pos] = x;
	}
	/// <summary>
	/// return the minimum element and remove it
	/// this is an O(log n) operation
	/// </summary>
	/// <returns>the minimum</returns>
	public T Dequeue()
	{
		var value = list[0];
		var x = list[--Count];
		list.RemoveAt(Count);
		if (Count == 0) return value;
		var pos = 0;
		while (pos * 2 + 1 < Count)
		{
			var a = 2 * pos + 1;
			var b = 2 * pos + 2;
			if (b < Count && comp(list[b], list[a]) < 0) a = b;
			if (comp(list[a], x) >= 0) break;
			list[pos] = list[a];
			pos = a;
		}
		list[pos] = x;
		return value;
	}
	/// <summary>
	/// look at the minimum element
	/// this is an O(1) operation
	/// </summary>
	/// <returns>the minimum</returns>
	public T Peek() => list[0];
	public IEnumerator<T> GetEnumerator() { var x = (PriorityQueue<T>)Clone(); while (x.Count > 0) yield return x.Dequeue(); }
	void CopyTo(Array array, int index) { foreach (var x in this) array.SetValue(x, index++); }
	public object Clone() { var x = new PriorityQueue<T>(comp, Count) { Count = Count }; x.list.AddRange(list); return x; }
	public void Clear() { list = new List<T>(); Count = 0; }
	public void TrimExcess() => list.TrimExcess();
	/// <summary>
	/// check whether item is in this queue
	/// this is an O(n) operation
	/// </summary>
	public bool Contains(T item) => list.Contains(item);
	IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
	void ICollection.CopyTo(Array array, int index) => CopyTo(array, index);
	bool ICollection.IsSynchronized => false;
	object ICollection.SyncRoot => this;
}
class AVLTree<T> : IEnumerable<T>, ICollection<T>, ICollection, IEnumerable
{
	public class AVLNode : IEnumerable<T>
	{
		readonly AVLTree<T> tree;
		public int Height { get; private set; }
		public int Bias => Left.Height - Right.Height;
		public T Item;
		public AVLNode? Parent;
		public AVLNode Left;
		public AVLNode Right;
		AVLNode(T x, AVLTree<T> tree) { this.tree = tree; Item = x; Left = tree.sentinel; Right = tree.sentinel; }
		public AVLNode(AVLTree<T> tree) : this(default!, tree) { Height = 0; Parent = null; }
		public AVLNode(T x, AVLNode parent, AVLTree<T> tree) : this(x, tree) { Height = 1; Parent = parent; }
		public void Adjust() => Height = 1 + Math.Max(Left.Height, Right.Height);
		public void ResetAsSentinel() { Height = 0; Left = tree.sentinel; Right = tree.sentinel; }
		public IEnumerator<T> GetEnumerator()
		{
			if (this != tree.sentinel)
			{
				foreach (var x in Left) yield return x;
				yield return Item;
				foreach (var x in Right) yield return x;
			}
		}
		public void SetLeft(AVLNode u) { Left = u; u.Parent = this; }
		public void SetRight(AVLNode u) { Right = u; u.Parent = this; }
		public void SetLR(bool is_left, AVLNode u) { if (is_left) SetLeft(u); else SetRight(u); }
		public bool IsLeftOfParent => Parent!.Left == this;
		IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
	}
	readonly AVLNode sentinel;
	readonly Comparison<T> comp;
	readonly Func<T, T, bool> equals;
	int count;
	// assumed to be comparer
	// i.e. comp(x,x)=0, and comp(x,y)>0 then comp(y,x)<0, and comp(x,y)>0 & comp(y,z)>0 then comp(x,z)>0
	public AVLTree(Comparison<T> comp)
	{
		sentinel = new AVLNode(this);
		sentinel.ResetAsSentinel();
		this.comp = comp ?? DefaultComparison<T>();
		if (typeof(T).IsValueType) equals = (x, y) => x!.Equals(y);
		else equals = (x, y) => ReferenceEquals(x, y);
		count = 0;
	}
	public AVLTree(IComparer<T>? comp = null) : this(comp.ToComparison()) { }
	// u must have non-null parent
	void Replace(AVLNode u, AVLNode v) => u.Parent!.SetLR(u.IsLeftOfParent, v);
	AVLNode RotateL(AVLNode v)
	{
		var u = v.Right;
		Replace(v, u);
		v.SetRight(u.Left);
		u.SetLeft(v);
		v.Adjust();
		u.Adjust();
		return u;
	}
	AVLNode RotateR(AVLNode u)
	{
		var v = u.Left;
		Replace(u, v);
		u.SetLeft(v.Right);
		v.SetRight(u);
		u.Adjust();
		v.Adjust();
		return v;
	}
	AVLNode RotateLR(AVLNode t) { RotateL(t.Left); return RotateR(t); }
	AVLNode RotateRL(AVLNode t) { RotateR(t.Right); return RotateL(t); }
	void Adjust(bool isInsertMode, AVLNode node)
	{
		while (node.Parent != sentinel)
		{
			var parent = node.Parent!;
			var height = parent.Height;
			if ((parent.Left == node) == isInsertMode)
				if (parent.Bias == 2) parent = parent.Left.Bias >= 0 ? RotateR(parent) : RotateLR(parent);
				else parent.Adjust();
			else
				if (parent.Bias == -2) parent = parent.Right.Bias <= 0 ? RotateL(parent) : RotateRL(parent);
			else parent.Adjust();
			if (height == parent.Height) break;
			node = parent;
		}
	}
	public void Add(T item)
	{
		var parent = sentinel;
		var pos = sentinel.Left;
		var isLeft = true;
		count++;
		while (pos != sentinel)
			if (comp(item, pos.Item) < 0) { parent = pos; pos = pos.Left; isLeft = true; }
			else { parent = pos; pos = pos.Right; isLeft = false; }
		if (isLeft)
			Adjust(true, parent.Left = new AVLNode(item, parent, this));
		else
			Adjust(true, parent.Right = new AVLNode(item, parent, this));
	}
	// if equals(x,y) holds then !(comp(x,y)<0) and !(comp(x,y)>0) must hold
	// i.e. equals(x,y) -> comp(x,y)=0
	public bool Remove(T item, AVLNode start)
	{
		var pos = start;
		while (pos != sentinel)
		{
			if (comp(item, pos.Item) < 0) pos = pos.Left;
			else if (comp(item, pos.Item) > 0) pos = pos.Right;
			else if (equals(pos.Item, item))
			{
				if (pos.Left == sentinel)
				{
					Replace(pos, pos.Right);
					Adjust(false, pos.Right);
				}
				else
				{
					var max = Max(pos.Left);
					pos.Item = max.Item;
					Replace(max, max.Left);
					Adjust(false, max.Left);
				}
				count--;
				return true;
			}
			else return Remove(item, pos.Left) || Remove(item, pos.Right);
		}
		return false;
	}
	public bool Remove(T item) => Remove(item, sentinel.Left);
	AVLNode Max(AVLNode node)
	{
		while (node.Right != sentinel) node = node.Right;
		return node;
	}
	AVLNode Min(AVLNode node)
	{
		while (node.Left != sentinel) node = node.Left;
		return node;
	}
	public bool Contains(T item)
	{
		var pos = sentinel.Left;
		while (pos != sentinel)
		{
			if (comp(item, pos.Item) < 0) pos = pos.Left;
			else if (comp(item, pos.Item) > 0) pos = pos.Right;
			else return true;
		}
		return false;
	}
	public T Find(T item)
	{
		var pos = sentinel.Left;
		while (pos != sentinel)
		{
			if (comp(item, pos.Item) < 0) pos = pos.Left;
			else if (comp(item, pos.Item) > 0) pos = pos.Right;
			else return pos.Item;
		}
		return default!;
	}
	public AVLNode? LowerBound(Predicate<T> pred) => LowerBound(pred, sentinel.Left);
	public AVLNode? UpperBound(Predicate<T> pred) => UpperBound(pred, sentinel.Left);
	public AVLNode? LowerBound(T item) => LowerBound(x => comp(x, item) >= 0);
	public AVLNode? UpperBound(T item) => UpperBound(x => comp(x, item) <= 0);
	AVLNode? UpperBound(Predicate<T> pred, AVLNode node) => node == sentinel ? null : pred(node.Item) ? UpperBound(pred, node.Right) ?? node : UpperBound(pred, node.Left);
	AVLNode? LowerBound(Predicate<T> pred, AVLNode node) => node == sentinel ? null : pred(node.Item) ? LowerBound(pred, node.Left) ?? node : LowerBound(pred, node.Right);
	public T Min() => Min(sentinel.Left).Item;
	public AVLNode MinNode() => Min(sentinel.Left);
	public T Max() => Max(sentinel.Left).Item;
	public AVLNode MaxNode() => Max(sentinel.Left);
	public bool IsEmpty => sentinel.Left == sentinel;
	public void Clear() { sentinel.Left = sentinel; count = 0; sentinel.ResetAsSentinel(); }
	public IEnumerator<T> GetEnumerator() => sentinel.Left.GetEnumerator();
	IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
	public void CopyTo(T[] array, int arrayIndex) { foreach (var x in this) array[arrayIndex++] = x; }
	public int Count => count;
	public bool IsReadOnly => true;
	public void CopyTo(Array array, int index) { foreach (var x in this) array.SetValue(x, index++); }
	public bool IsSynchronized => false;
	public object SyncRoot => this;
}