Problem:
Score : 100 points

Problem Statement

There are N flowers arranged in a row.
For each i (1 \leq i \leq N), the height and the beauty of the i-th flower from the left is h_i and a_i, respectively.
Here, h_1, h_2, \ldots, h_N are all distinct.

Taro is pulling out some flowers so that the following condition is met:

The heights of the remaining flowers are monotonically increasing from left to right.

Find the maximum possible sum of the beauties of the remaining flowers.

Constraints

All values in input are integers.

1 \leq N \leq 2 × 10^5

1 \leq h_i \leq N

h_1, h_2, \ldots, h_N are all distinct.

1 \leq a_i \leq 10^9

Input

Input is given from Standard Input in the following format:

N
h_1 h_2 \ldots h_N
a_1 a_2 \ldots a_N

Output

Print the maximum possible sum of the beauties of the remaining flowers.

Sample Input 1

4
3 1 4 2
10 20 30 40

Sample Output 1

60

We should keep the second and fourth flowers from the left.
Then, the heights would be 1, 2 from left to right, which is monotonically increasing, and the sum of the beauties would be 20 + 40 = 60.

Sample Input 2

1
1
10

Sample Output 2

10

The condition is met already at the beginning.

Sample Input 3

5
1 2 3 4 5
1000000000 1000000000 1000000000 1000000000 1000000000

Sample Output 3

5000000000

The answer may not fit into a 32-bit integer type.

Sample Input 4

9
4 2 5 8 3 6 1 7 9
6 8 8 4 6 3 5 7 5

Sample Output 4

31

We should keep the second, third, sixth, eighth and ninth flowers from the left.

Solution in C# (Mono 4.6.2.0) (judge verdict: Accepted)

using System;
using System.Linq;//リストの使用
using System.Collections.Generic;
class Program
{
static string[] input = Console.ReadLine().Split(' ');
static int n = int.Parse(input[0]);
static long[] nums = new long[450*450];
static long[] numSets = new long[450];//450*450に分割
static long[] numSetsSub = new long[450];

	static void Main()
	{
    PointChangeMaxGetReady();
      //1点の値を全てchangeNumに変更し、区間以上以下の最大値を求める初期値前処理。

    int[] heights = Array.ConvertAll(Console.ReadLine().Split(' '),int.Parse);
    long[] values = Array.ConvertAll(Console.ReadLine().Split(' '),long.Parse);

    for(int i = 0; i < n; i++)
    {
      PointChangeMaxGet(heights[i], 
        PointChangeMaxGetAnswer(0,heights[i]-1) + values[i]);
    }
    
    Console.WriteLine(PointChangeMaxGetAnswer(0,n));
	}

  static void PointChangeMaxMinGetReady()
  {//1点の値をchangeNumに変更し、区間以上以下の最大値1最小値-1を求める初期値前処理。
    for(int i = 0; i < 450*450; i++)
    {
      nums[i] = 0;//初期値
    }
    for(int i = 0; i < 450; i++)
    {
      numSets[i] = 0;
    }
  }

  static void PointChangeMaxGetReady()
  {
    PointChangeMaxMinGetReady();
  }

  static void PointChangeMinGetReady()
  {
    PointChangeMaxMinGetReady();
  }

  static void AreaChangeSumGetReady()
  {//区間以上以下の値を全てchangeNumに変更し、区間以上以下の和を求める初期値前処理。
  for(int i = 0; i < 450*450; i++)
  {
    nums[i] = 0;//初期値
  }
  for(int i = 0; i < 450; i++)
  {
    numSetsSub[i] = long.MinValue/2;
    for(int j = 0; j < 450; j++)
    {
      numSets[i] += nums[450*i+j];//区間の和
    }
  }
  }

  static void AreaChangeMaxMinGetReady(int minOrMax)
  {//区間以上以下の値を全てchangeNumに変更し、区間以上以下の最大値1最小値-1を求める初期値前処理。
    for(int i = 0; i < 450*450; i++)
    {
      nums[i] = 0;//初期値
    }
    for(int i = 0; i < 450; i++)
    {
      long max = long.MinValue/2;
      long min = long.MaxValue/2;
      for(int j = 0; j < 450; j++)
      {
        max = Math.Max(max, nums[450*i+j]);
        min = Math.Min(min, nums[450*i+j]);
      }
      if(minOrMax == -1)
      {
        numSets[i] = min;
        numSetsSub[i] = long.MinValue/2;
      }else
      {
        numSets[i] = max;
        numSetsSub[i] = long.MaxValue/2;
      }
    } 
  }

  static void AreaChangeMaxGetReady()
  {//区間以上以下の値を全てchangeNumに変更し、区間以上以下の最大値を求める初期値前処理。
    AreaChangeMaxMinGetReady(1);
  }

  static void AreaChangeMinGetReady()
  {//区間以上以下の値を全てchangeNumに変更し、区間以上以下の最小値を求める初期値前処理。
    AreaChangeMaxMinGetReady(-1);
  }

  static void AreaChangePointGetReady()
  {//区間以上以下の値を全てchangeNumに変更し、ある１点の値を求める初期値前処理。
    AreaChangeMinGetReady();
  }

  static void AreaAddSumGetReady()
  {//区間以上以下の値に全てchangeNum加算し、区間以上以下の和を求める初期値前処理。
    for(int i = 0; i < 450*450; i++)
    {
      nums[i] = 0;//初期値
    }
    for(int i = 0; i < 450; i++)
    {
      numSets[i] = 0;
      for(int j = 0; j < 450; j++)
      {
        numSetsSub[i] += nums[450*i+j];//区間の和
      }
    }
  }

  static void AreaAddMaxMinGetReady(int minOrMax)
  {//区間以上以下の値に全てchangeNum加算し、区間以上以下の最大値1または最小値-1を求める初期値前処理。
    for(int i = 0; i < 450*450; i++)
    {
      nums[i] = 0;//初期値
    }
    for(int i = 0; i < 450; i++)
    {
      numSets[i] = 0;
      if(minOrMax == -1)
      {
        long min = long.MaxValue/2;
        for(int j = 0; j < 450; j++)
        {
          min = Math.Min(min, nums[450*i+j]);
        }
        numSetsSub[i] = min;//各区間の最小値
      }else
      {
        long max = long.MinValue/2;
        for(int j = 0; j < 450; j++)
        {
          max = Math.Max(max, nums[450*i+j]);
        }
        numSetsSub[i] = max;//各区間の最小値
      }
    }
  }

  static void AreaAddMaxGetReady()
  {//区間以上以下の値に全てchangeNum加算し、区間以上以下の最大値を求める初期値前処理。
    AreaAddMaxMinGetReady(1);
  }

  static void AreaAddMinGetReady()
  {//区間以上以下の値に全てchangeNum加算し、区間以上以下の最小値を求める初期値前処理。
    AreaAddMaxMinGetReady(-1);
  }

  static void PointChangeMaxMinGet(int pointNum, long changeNum, int minOrMax)
  {//1点の値をchangeNumに変更し、区間以上以下の最小値-1最大値1を求める。入力側
    int pointPosition = WherePosition(pointNum);

    nums[pointNum] = changeNum;

    if(minOrMax == 1)
    {
      numSets[pointPosition] = 0;
      for(int i = 450*pointPosition; i < 450*(pointPosition+1); i++)
      {
        numSets[pointPosition] = Math.Max(numSets[pointPosition], nums[i]);
      }
    }else
    {
      numSets[pointPosition] = long.MaxValue;
      for(int i = 450*pointPosition; i < 450*(pointPosition+1); i++)
      {
        numSets[pointPosition] = Math.Min(numSets[pointPosition], nums[i]);
      }
    }
  }

  static void PointChangeMaxGet(int pointNum, long changeNum)
  {
    PointChangeMaxMinGet(pointNum, changeNum,1);
  }

  static void PointChangeMinGet(int pointNum, long changeNum)
  {
    PointChangeMaxMinGet(pointNum, changeNum,-1);
  }

  static void AreaChangeSumGet(int leftNum, int rightNum, long changeNum)
  {//区間以上以下の値を全てchangeNumに変更し、区間以上以下の和を求める。入力側
    int leftPosition = WherePosition(leftNum);
    int rightPosition = WherePosition(rightNum);

    NumberApply(leftNum, rightNum);

    if(leftPosition == rightPosition)//左右が同じ分類のとき
    {
      for(long i = leftNum; i <= rightNum; i++)
      {
        nums[i] = changeNum;
      }
      long sum = 0;
      for(long i = 0; i < 450; i++)//区間内全てを見る
      {
        sum += nums[leftPosition*450+i];
      }
      numSets[leftPosition] = sum;
    }else
    {
      for(long i = leftNum; i < 450*(leftPosition+1); i++)//左区間内（左端より右だけ見る）
      {
        nums[i] = changeNum;
      }
      for(long i = 450*rightPosition; i <= rightNum; i++)//右区間内
      {
        nums[i] = changeNum;
      }
      long sumL = 0;
      long sumR = 0;
      for(long i = 0; i < 450; i++)//区間内全てを見る
      {
        sumL += nums[leftPosition*450+i];
        sumR += nums[rightPosition*450+i];
      }
      numSets[leftPosition] = sumL;
      numSets[rightPosition] = sumR;
      
      for(int i = leftPosition+1; i < rightPosition; i++)//見ていない区間内
      {
        numSetsSub[i] = changeNum;
        numSets[i] = changeNum*450;
      }
    }
  }

  static void AreaChangeMaxMinGet(int leftNum, int rightNum, long changeNum, int minOrMax)
  {//区間以上以下の値を全てchangeNumに変更し、区間以上以下の最小値-1最大値1を求める。入力側
    int leftPosition = WherePosition(leftNum);
    int rightPosition = WherePosition(rightNum);

    NumberApply(leftNum, rightNum);

    if(leftPosition == rightPosition)//左右が同じ分類のとき
    {
      for(long i = leftNum; i <= rightNum; i++)
      {
        nums[i] = changeNum;
      }
      long minMemo = long.MaxValue/2;
      long maxMemo = long.MinValue/2;
      for(long i = 0; i < 450; i++)//区間内全てを見る
      {
        minMemo = Math.Min(minMemo, nums[leftPosition*450+i]);
        maxMemo = Math.Max(maxMemo, nums[leftPosition*450+i]);
      }
      if(minOrMax == -1) numSets[leftPosition] = minMemo;
      if(minOrMax == 1) numSets[leftPosition] = maxMemo;
    }else
    {
      for(long i = leftNum; i < 450*(leftPosition+1); i++)//左区間内（左端より右だけ見る）
      {
        nums[i] = changeNum;
      }
      for(long i = 450*rightPosition; i <= rightNum; i++)//右区間内
      {
        nums[i] = changeNum;
      }
      long minMemoL = long.MaxValue/2;
      long minMemoR = long.MaxValue/2;
      long maxMemoL = long.MaxValue/2;
      long maxMemoR = long.MaxValue/2;
      for(long i = 0; i < 450; i++)//区間内全てを見る
      {
        minMemoL = Math.Min(minMemoL, nums[leftPosition*450+i]);
        minMemoR = Math.Min(minMemoR, nums[rightPosition*450+i]);
        maxMemoL = Math.Max(maxMemoL, nums[leftPosition*450+i]);
        maxMemoR = Math.Max(maxMemoR, nums[rightPosition*450+i]);
      }
      if(minOrMax == -1)
      {
        numSets[leftPosition] = minMemoL;
        numSets[rightPosition] = minMemoR;
      }else
      {
        numSets[leftPosition] = maxMemoL;
        numSets[rightPosition] = maxMemoR;
      }
      
      for(int i = leftPosition+1; i < rightPosition; i++)//見ていない区間内
      {
        numSetsSub[i] = changeNum;
        numSets[i] = changeNum;
      }
    }
  }

  static void AreaChangeMaxGet(int leftNum, int rightNum, long changeNum)
  {//区間以上以下の値を全てchangeNumに変更し、区間以上以下の最大値を求める。入力側
    AreaChangeMaxMinGet(leftNum, rightNum, changeNum, 1);
  }

  static void AreaChangeMinGet(int leftNum, int rightNum, long changeNum)
  {//区間以上以下の値を全てchangeNumに変更し、区間以上以下の最小値を求める。入力側
    AreaChangeMaxMinGet(leftNum, rightNum, changeNum, -1);
  }

  static void AreaChangePointGet(int leftNum, int rightNum, long changeNum)
  {//区間以上以下の値を全てchangeNumに変更し、ある１点の値を求める。入力側
    AreaChangeMinGet(leftNum, rightNum, changeNum);
  }

  static void AreaAddSumGet(int leftNum, int rightNum, long changeNum)
  {//区間以上以下の値に全てchangeNum加算し、区間以上以下の和を求める。入力側
    int leftPosition = WherePosition(leftNum);
    int rightPosition = WherePosition(rightNum);

    if(leftPosition == rightPosition)//左右が同じ分類のとき
    {
      for(long i = leftNum; i <= rightNum; i++)
      {
        nums[i] += changeNum;
        numSetsSub[leftPosition] += changeNum;
      }
    }else
    {
      for(long i = leftNum; i < 450*(leftPosition+1); i++)//左区間内（左端より右だけ見る）
      {
        nums[i] += changeNum;
        numSetsSub[leftPosition] += changeNum;
      }
      for(long i = 450*rightPosition; i <= rightNum; i++)//右区間内
      {
        nums[i] += changeNum;
        numSetsSub[rightPosition] += changeNum;
      }
      for(int i = leftPosition+1; i < rightPosition; i++)//見ていない区間内
      {
        numSetsSub[i] += changeNum*450;
        numSets[i] += changeNum;
      }
    }
  }

  static void AreaAddMaxMinGet(int leftNum, int rightNum, long changeNum, int minOrMax)
  {//区間以上以下の値に全てchangeNum加算し、区間以上以下の最大値1最小値-1を求める。入力側
    int leftPosition = WherePosition(leftNum);
    int rightPosition = WherePosition(rightNum);

    if(minOrMax == -1) NumberAddMin(leftNum, rightNum);
    else NumberAddMax(leftNum, rightNum);

    if(leftPosition == rightPosition)//左右が同じ分類のとき
    {
      for(long i = leftNum; i <= rightNum; i++)
      {
        nums[i] += changeNum;
      }
    if(minOrMax == -1) NumberAddMin(leftNum);
    else NumberAddMax(leftNum);
    }else
    {
      for(long i = leftNum; i < 450*(leftPosition+1); i++)//左区間内（左端より右だけ見る）
      {
        nums[i] += changeNum;
      }
      for(long i = 450*rightPosition; i <= rightNum; i++)//右区間内
      {
        nums[i] += changeNum;
      }
      if(minOrMax == -1) NumberAddMin(leftNum,rightNum);
      else NumberAddMax(leftNum,rightNum);
    
      for(int i = leftPosition+1; i < rightPosition; i++)//見ていない区間内
      {
        numSetsSub[i] += changeNum;
        numSets[i] += changeNum;
      }
    }
  }

  static void AreaAddMaxGet(int leftNum, int rightNum, long changeNum)
  {//区間以上以下の値に全てchangeNum加算し、区間以上以下の最大値を求める。入力側
    AreaAddMaxMinGet(leftNum, rightNum, changeNum, 1);
  }

  static void AreaAddMinGet(int leftNum, int rightNum, long changeNum)
  {//区間以上以下の値に全てchangeNum加算し、区間以上以下の最小値を求める。入力側
    AreaAddMaxMinGet(leftNum, rightNum, changeNum, -1);
  }

  static long PointChangeMaxMinGetAnswer(int leftNum, int rightNum, int minOrMax)
  {//1点の値をchangeNumに変更し、区間以上以下の最大値1最小値-1を求める。出力側
    long minMemo = long.MaxValue/2;
    long maxMemo = long.MinValue/2;
    int leftPosition = WherePosition(leftNum);
    int rightPosition = WherePosition(rightNum);

    if(leftPosition == rightPosition)
    {
      for(long i = leftNum; i <= rightNum; i++)//左右が同じ分類のとき
      {
        minMemo = Math.Min(minMemo, nums[i]);
        maxMemo = Math.Max(maxMemo, nums[i]);
      }
    }else
    {
      for(long i = leftNum; i < 450*(leftPosition+1); i++)//左区間内（左端より右だけ見る）
      {
        minMemo = Math.Min(minMemo, nums[i]);
        maxMemo = Math.Max(maxMemo, nums[i]);
      }
      for(long i = 450*rightPosition; i <= rightNum; i++)//右区間内
      {
        minMemo = Math.Min(minMemo, nums[i]);
        maxMemo = Math.Max(maxMemo, nums[i]);
      }
      for(long i = leftPosition+1; i < rightPosition; i++)//見ていない区間内
      {
        minMemo = Math.Min(minMemo, numSets[i]);
        maxMemo = Math.Max(maxMemo, numSets[i]);
      }
    }
    if(minOrMax == -1) return minMemo;
    return maxMemo;
  }

  static long PointChangeMaxGetAnswer(int leftNum, int rightNum)
  {
    return PointChangeMaxMinGetAnswer(leftNum, rightNum, 1);
  }

  static long PointChangeMinGetAnswer(int leftNum, int rightNum)
  {
    return PointChangeMaxMinGetAnswer(leftNum, rightNum, -1);
  }

  static long AreaChangeSumGetAnswer(int leftNum, int rightNum)
  {//区間以上以下の値に全てchangeNum加算し、区間以上以下の和を求める。出力側
    long sum = 0;
    int leftPosition = WherePosition(leftNum);
    int rightPosition = WherePosition(rightNum);
    NumberApply(leftNum, rightNum);

    if(leftPosition == rightPosition)
    {
      for(long i = leftNum; i <= rightNum; i++)//左右が同じ分類のとき
      {
        sum += nums[i];
      }
    }else
    {
      for(long i = leftNum; i < 450*(leftPosition+1); i++)//左区間内（左端より右だけ見る）
      {
        sum += nums[i];
      }
      for(long i = 450*rightPosition; i <= rightNum; i++)//右区間内
      {
        sum += nums[i];
      }
      for(long i = leftPosition+1; i < rightPosition; i++)//見ていない区間内
      {
        sum += numSets[i];
      }
    }
    return sum;
  }

  static long AreaChangeMaxMinGetAnswer(int leftNum, int rightNum, int minOrMax)
  {//区間以上以下の値を全てchangeNumに変更し、区間以上以下の最大値1最小値-1を求める。出力側
    long minMemo = long.MaxValue/2;
    long maxMemo = long.MinValue/2;
    int leftPosition = WherePosition(leftNum);
    int rightPosition = WherePosition(rightNum);

    NumberApply(leftNum, rightNum);

    if(leftPosition == rightPosition)
    {
      for(long i = leftNum; i <= rightNum; i++)//左右が同じ分類のとき
      {
        minMemo = Math.Min(minMemo, nums[i]);
        maxMemo = Math.Max(maxMemo, nums[i]);
      }
    }else
    {
      for(long i = leftNum; i < 450*(leftPosition+1); i++)//左区間内（左端より右だけ見る）
      {
        minMemo = Math.Min(minMemo, nums[i]);
        maxMemo = Math.Max(maxMemo, nums[i]);
      }
      for(long i = 450*rightPosition; i <= rightNum; i++)//右区間内
      {
        minMemo = Math.Min(minMemo, nums[i]);
        maxMemo = Math.Max(maxMemo, nums[i]);
      }
      for(long i = leftPosition+1; i < rightPosition; i++)//見ていない区間内
      {
        minMemo = Math.Min(minMemo, numSets[i]);
        maxMemo = Math.Max(maxMemo, numSets[i]);
      }
    }
    if(minOrMax == -1) return minMemo;
    return maxMemo;
  }

  static long AreaChangeMaxGetAnswer(int leftNum, int rightNum)
  {//区間以上以下の値を全てchangeNumに変更し、区間以上以下の最大値を求める。出力側
    return AreaChangeMaxMinGetAnswer(leftNum, rightNum, 1);
  }

  static long AreaChangeMinGetAnswer(int leftNum, int rightNum)
  {//区間以上以下の値を全てchangeNumに変更し、区間以上以下の最大値を求める。出力側
    return AreaChangeMaxMinGetAnswer(leftNum, rightNum, -1);
  }

  static long AreaChangePointGetAnswer(int pointNum)
  {//区間以上以下の値を全てchangeNumに変更し、ある１点の値を求める。出力側
    int numPosition = WherePosition(pointNum);

    NumberApply(pointNum);

    return nums[pointNum];
  }

  static long AreaAddSumGetAnswer(int leftNum, int rightNum)
  {//区間以上以下の値に全てchangeNum加算し、区間以上以下の和を求める。出力側
    long sum = 0;
    int leftPosition = WherePosition(leftNum);
    int rightPosition = WherePosition(rightNum);

    if(leftPosition == rightPosition)
    {
      for(long i = leftNum; i <= rightNum; i++)//左右が同じ分類のとき
      {
        sum += numSets[leftPosition] + nums[i];
      }
    }else
    {
      for(long i = leftNum; i < 450*(leftPosition+1); i++)//左区間内（左端より右だけ見る）
      {
        sum += numSets[leftPosition] + nums[i];
      }
      for(long i = 450*rightPosition; i <= rightNum; i++)//右区間内
      {
        sum += numSets[rightPosition] + nums[i];
      }
      for(long i = leftPosition+1; i < rightPosition; i++)//見ていない区間内
      {
        sum += numSetsSub[i];
      }
    }
    return sum;
  }

  static long AreaAddMaxMinGetAnswer(int leftNum, int rightNum, int minOrMax)
  {//区間以上以下の値に全てchangeNum加算し、区間以上以下の最大値1最小値-1を求める。出力側
    int leftPosition = WherePosition(leftNum);
    int rightPosition = WherePosition(rightNum);
    long min = long.MaxValue/2;
    long max = long.MinValue/2;
    
    if(minOrMax == -1) NumberAddMin(leftNum, rightNum);
    else NumberAddMax(leftNum, rightNum);

    if(leftPosition == rightPosition)
    {
      for(long i = leftNum; i <= rightNum; i++)//左右が同じ分類のとき
      {
        min = Math.Min(min, nums[i]);
        max = Math.Max(max, nums[i]);
      }
    }else
    {
      for(long i = leftNum; i < 450*(leftPosition+1); i++)//左区間内（左端より右だけ見る）
      {
        min = Math.Min(min, nums[i]);
        max = Math.Max(max, nums[i]);
      }
      for(long i = 450*rightPosition; i <= rightNum; i++)//右区間内
      {
        min = Math.Min(min, nums[i]);
        max = Math.Max(max, nums[i]);
      }
      for(long i = leftPosition+1; i < rightPosition; i++)//見ていない区間内
      {
        min = Math.Min(min, numSetsSub[i]);
        max = Math.Max(max, numSetsSub[i]);
      }
    }
    if(minOrMax == -1) return min;
    else return max;
  }

  static long AreaAddMaxGetAnswer(int leftNum, int rightNum)
  {//区間以上以下の値に全てchangeNum加算し、区間以上以下の最大値を求める。出力側
    return AreaAddMaxMinGetAnswer(leftNum, rightNum, 1);
  }

  static long AreaAddMinGetAnswer(int leftNum, int rightNum)
  {//区間以上以下の値に全てchangeNum加算し、区間以上以下の最小値を求める。出力側
    return AreaAddMaxMinGetAnswer(leftNum, rightNum, -1);
  }

  static void NumberApply(int pointNum)
  {//控え中の数を個々に割り当てる
    int numPosition = WherePosition(pointNum);

    if(numSetsSub[numPosition] != long.MinValue/2)
    {
      for(int i = 0; i < 450; i++)//区間内全てを見る
      {
        nums[numPosition*450+i] = numSetsSub[numPosition];
      }
      numSetsSub[numPosition] = long.MinValue/2;
    }
  }

  static void NumberApply(int leftNum, int rightNum)
  {
    NumberApply(leftNum);
    NumberApply(rightNum);
  }

  static void NumberAddMax(int pointNum)
  {//控え中の数を個々に加算した後、最大値を求める
    int numPosition = WherePosition(pointNum);

    if(numSets[numPosition] != 0)
    {
      for(int i = 0; i < 450; i++)//区間内全てを見る
      {
        nums[numPosition*450+i] += numSets[numPosition];
      }
      numSets[numPosition] = 0;
    }

    long max = long.MinValue/2;
    for(int i = 0; i < 450; i++)
    {
      if(nums[numPosition*450+i] > max) max = nums[numPosition*450+i];
    }

    numSetsSub[numPosition] = max;
  }

  static void NumberAddMin(int pointNum)
  {//控え中の数を個々に加算した後、最小値を求める
    int numPosition = WherePosition(pointNum);

    if(numSets[numPosition] != 0)
    {
      for(int i = 0; i < 450; i++)//区間内全てを見る
      {
        nums[numPosition*450+i] += numSets[numPosition];
      }
      numSets[numPosition] = 0;
    }

    long min = long.MaxValue/2;
    for(int i = 0; i < 450; i++)
    {
      if(nums[numPosition*450+i] < min) min = nums[numPosition*450+i];
    }

    numSetsSub[numPosition] = min;
  }

  static void NumberAddMin(int leftNum, int rightNum)
  {
    NumberAddMin(leftNum);
    NumberAddMin(rightNum);
  }

  static void NumberAddMax(int leftNum, int rightNum)
  {
    NumberAddMax(leftNum);
    NumberAddMax(rightNum);
  }

  static int WherePosition(int num)//左から何番目の分類に属するか
  {
    return num / 450;
  }
  
}