Problem:
Score : 500 points

Problem Statement

There is an infinitely long street that runs west to east, which we consider as a number line.

There are N roadworks scheduled on this street.
The i-th roadwork blocks the point at coordinate X_i from time S_i - 0.5 to time T_i - 0.5.

Q people are standing at coordinate 0. The i-th person will start the coordinate 0 at time D_i, continue to walk with speed 1 in the positive direction and stop walking when reaching a blocked point.

Find the distance each of the Q people will walk.

Constraints

All values in input are integers.

1 \leq N, Q \leq 2 \times 10^5

0 \leq S_i < T_i \leq 10^9

1 \leq X_i \leq 10^9

0 \leq D_1 < D_2 < ... < D_Q \leq 10^9

If i \neq j and X_i = X_j, the intervals [S_i, T_i) and [S_j, T_j) do not overlap.

Input

Input is given from Standard Input in the following format:

N Q
S_1 T_1 X_1
:
S_N T_N X_N
D_1
:
D_Q

Output

Print Q lines. The i-th line should contain the distance the i-th person will walk or -1 if that person walks forever.

Sample Input 1

4 6
1 3 2
7 13 10
18 20 13
3 4 2
0
1
2
3
5
8

Sample Output 1

2
2
10
-1
13
-1

The first person starts coordinate 0 at time 0 and stops walking at coordinate 2 when reaching a point blocked by the first roadwork at time 2.

The second person starts coordinate 0 at time 1 and reaches coordinate 2 at time 3. The first roadwork has ended, but the fourth roadwork has begun, so this person also stops walking at coordinate 2.

The fourth and sixth persons encounter no roadworks while walking, so they walk forever. The output for these cases is -1.

Solution in C# (Mono 4.6.2.0) (judge verdict: Wrong Answer)

using System;
using System.Linq;//リストの使用
using System.Collections.Generic;
using System.Text;//テキストの高速出力に必要
class Program
{
static long[] compressedX;//[i]は、iに圧縮前の座標
static long[] compressedY;
static long[] nums = new long[600*600];
static long[] numSets = new long[600];//600*600に分割
static long[] numSetsSub = new long[600];

	static void Main()
	{
		string[] input = Console.ReadLine().Split(' ');
		int n = int.Parse(input[0]);
		int q = int.Parse(input[1]);
    long[,] vertexes = new long[n,3];
    for(long i = 0; i < n; i++)
    {
      long[] numsa = Array.ConvertAll(Console.ReadLine().Split(' '),long.Parse);
      vertexes[i,0] = numsa[0];
      vertexes[i,1] = numsa[1];
      vertexes[i,2] = numsa[2];
    }
    long[,] times = new long[2*n+q,2];
    for(int i = 0; i < n; i++)
    {
      times[i,0] = vertexes[i,0]-vertexes[i,2];
      times[n+i,0] = vertexes[i,1]-vertexes[i,2]-1;
      times[i,1] = i;
      times[n+i,1] = n+i;
    }
    for(int i = 0; i < q; i++)
    {
      times[2*n+i,0] = long.Parse(Console.ReadLine());
      times[2*n+i,1] = 2*n+i;
    }

    long[,] afterTimes = CoordinateCompression(times);//1次元の座標圧縮

    long[][] timesSub = new long[n][];
    for(int i = 0; i < n; i++)
    {
      timesSub[i] = new long[3];
      timesSub[i][0] = afterTimes[i,2];
      timesSub[i][1] = afterTimes[n+i,2];
      timesSub[i][2] = vertexes[i,2];
    }
    Array.Sort(timesSub, (a, b) => b[2].CompareTo(a[2]));
    

	}

  static long[,] CoordinateCompression(long[,] vertexesOriginal)
    //1次元の座標圧縮。配列は0-indexで[x,順番]。compressedXも更新。
    //例えば、{2,4,4,3}は{0,2,2,1}を返す。
  {
    long n = vertexesOriginal.GetLength(0);//多次元配列の長さの取得
    long xCount = 1;//圧縮後のxの個数
    long[] compressedXmemo = new long[n];
    long[][] vertexes = new long[n][];
    for(long i = 0; i < n; i++)
    {
      vertexes[i] = new long[3];
      for(long j = 0; j < 2; j++)
      {
        vertexes[i][j] = vertexesOriginal[i,j];//配列をジャグ配列に置換
      }
    }

    Array.Sort(vertexes, (a, b) => a[0].CompareTo(b[0]));//x座標でソート
    vertexes[0][2] = 0;
    compressedXmemo[0] = vertexes[0][0];
    for(long i = 1; i < n; i++)
    {
      if(vertexes[i][0] == vertexes[i-1][0])//x座標が同じ
      {
        vertexes[i][2] = xCount - 1;
      }else
      {
        xCount++;
        vertexes[i][2] = xCount - 1;
        compressedXmemo[xCount-1] = vertexes[i][0];
      }
    }
    compressedX = new long[xCount];
    for(long i = 0; i < xCount; i++) compressedX[i] = compressedXmemo[i];

    Array.Sort(vertexes, (a, b) => a[1].CompareTo(b[1]));//もとの番号順でソート

    long[,] answer = new long[n,3];
    for(long i = 0; i < n; i++)
    {
      for(long j = 0; j < 3; j++)
      {
        answer[i,j] = vertexes[i][j];//ジャグ配列から戻す
      }
    }

    return answer;//[x,順番,圧縮x]を返す。
  }

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

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

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

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

   static void AreaAddMinGetReady()
   {//区間以上以下の値に全てchangeNum加算し、区間以上以下の最小値を求める初期値前処理。
     AreaAddMaxMinGetReady(-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 < 600; i++)//区間内全てを見る
       {
         sum += nums[leftPosition*600+i];
       }
       numSets[leftPosition] = sum;
     }else
     {
       for(long i = leftNum; i < 600*(leftPosition+1); i++)//左区間内（左端より右だけ見る）
       {
         nums[i] = changeNum;
       }
       for(long i = 600*rightPosition; i <= rightNum; i++)//右区間内
       {
         nums[i] = changeNum;
       }
       long sumL = 0;
       long sumR = 0;
       for(long i = 0; i < 600; i++)//区間内全てを見る
       {
         sumL += nums[leftPosition*600+i];
         sumR += nums[rightPosition*600+i];
       }
       numSets[leftPosition] = sumL;
       numSets[rightPosition] = sumR;
       
       for(int i = leftPosition+1; i < rightPosition; i++)//見ていない区間内
       {
         numSetsSub[i] = changeNum;
         numSets[i] = changeNum*600;
       }
     }
   }

   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 < 600; i++)//区間内全てを見る
       {
         minMemo = Math.Min(minMemo, nums[leftPosition*600+i]);
         maxMemo = Math.Max(maxMemo, nums[leftPosition*600+i]);
       }
       if(minOrMax == -1) numSets[leftPosition] = minMemo;
       if(minOrMax == 1) numSets[leftPosition] = maxMemo;
     }else
     {
       for(long i = leftNum; i < 600*(leftPosition+1); i++)//左区間内（左端より右だけ見る）
       {
         nums[i] = changeNum;
       }
       for(long i = 600*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 < 600; i++)//区間内全てを見る
       {
         minMemoL = Math.Min(minMemoL, nums[leftPosition*600+i]);
         minMemoR = Math.Min(minMemoR, nums[rightPosition*600+i]);
         maxMemoL = Math.Max(maxMemoL, nums[leftPosition*600+i]);
         maxMemoR = Math.Max(maxMemoR, nums[rightPosition*600+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 < 600*(leftPosition+1); i++)//左区間内（左端より右だけ見る）
       {
         nums[i] += changeNum;
         numSetsSub[leftPosition] += changeNum;
       }
       for(long i = 600*rightPosition; i <= rightNum; i++)//右区間内
       {
         nums[i] += changeNum;
         numSetsSub[rightPosition] += changeNum;
       }
       for(int i = leftPosition+1; i < rightPosition; i++)//見ていない区間内
       {
         numSetsSub[i] += changeNum*600;
         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 < 600*(leftPosition+1); i++)//左区間内（左端より右だけ見る）
       {
         nums[i] += changeNum;
       }
       for(long i = 600*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 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 < 600*(leftPosition+1); i++)//左区間内（左端より右だけ見る）
       {
         sum += nums[i];
       }
       for(long i = 600*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 < 600*(leftPosition+1); i++)//左区間内（左端より右だけ見る）
       {
         minMemo = Math.Min(minMemo, nums[i]);
         maxMemo = Math.Max(maxMemo, nums[i]);
       }
       for(long i = 600*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 < 600*(leftPosition+1); i++)//左区間内（左端より右だけ見る）
       {
         sum += numSets[leftPosition] + nums[i];
       }
       for(long i = 600*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 < 600*(leftPosition+1); i++)//左区間内（左端より右だけ見る）
       {
         min = Math.Min(min, nums[i]);
         max = Math.Max(max, nums[i]);
       }
       for(long i = 600*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 < 600; i++)//区間内全てを見る
       {
         nums[numPosition*600+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 < 600; i++)//区間内全てを見る
       {
         nums[numPosition*600+i] += numSets[numPosition];
       }
       numSets[numPosition] = 0;
     }

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

     numSetsSub[numPosition] = max;
   }

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

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

     long min = long.MaxValue/2;
     for(int i = 0; i < 600; i++)
     {
       if(nums[numPosition*600+i] < min) min = nums[numPosition*600+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 / 600;
   }
   
 }