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 (GCC 5.4.1) (judge verdict: Accepted)

#include <float.h>
#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

// 内部定数
#define D_SEGT_CNT		1048576									// セグメントツリーデータ数(2の累乗)
#define D_SEGT_INI		0										// セグメントツリー初期値
#define D_CONS_MAX		200000									// 最大工事数
#define D_HUM_MAX		200000									// 最大人数
#define D_TIME_MAX		D_CONS_MAX * 2 + D_HUM_MAX				// 最大時間数

// 内部構造体 - 工事情報
typedef struct Cons {
	int miTimeS;												// 開始時間
	int miTimeE;												// 終了時間
	int miPos;													// 位置
} Cons;

// 内部変数
static FILE *szpFpI;											// 入力
static Cons sz1Cons[D_CONS_MAX];								// 工事
static int siCCnt;												// 工事数
static int si1Hum[D_HUM_MAX];									// 出発時間[人]
static int siHCnt;												// 人数
static int si1Time[D_TIME_MAX];									// 時間
static int siTCnt;												// 時間数
static int si1SegT[D_SEGT_CNT * 2];								// セグメントツリー
static int siSCNo;												// セグメントツリー - 子の開始位置

// 内部変数 - テスト用
#ifdef D_TEST
	static int siRes;
	static FILE *szpFpA;
	static int siTNo;
#endif

// 出力
int
fOut(
	char *pcpLine				// <I> １行
)
{
	char lc1Buf[1024];

#ifdef D_TEST
	fgets(lc1Buf, sizeof(lc1Buf), szpFpA);
	if (strcmp(lc1Buf, pcpLine)) {
		siRes = -1;
	}
#else
	printf("%s", pcpLine);
#endif

	return 0;
}

// ソート関数 - int昇順
int
fSortFncIu(
	const void *pzpVal1			// <I> 値１
	, const void *pzpVal2		// <I> 値２
)
{
	int *lipVal1 = (int *)pzpVal1;
	int *lipVal2 = (int *)pzpVal2;

	// int昇順
	if (*lipVal1 > *lipVal2) {
		return 1;
	}
	else if (*lipVal1 < *lipVal2) {
		return -1;
	}

	return 0;
}

// ソート関数 - 工事 - 位置降順
int
fSortFncPd(
	const void *pzpVal1			// <I> 値１
	, const void *pzpVal2		// <I> 値２
)
{
	Cons *lzpVal1 = (Cons *)pzpVal1;
	Cons *lzpVal2 = (Cons *)pzpVal2;

	// 位置降順
	if (lzpVal1->miPos > lzpVal2->miPos) {
		return -1;
	}
	else if (lzpVal1->miPos < lzpVal2->miPos) {
		return 1;
	}

	return 0;
}

// 配列 - 重複カット
int
fCutDpl(
	int *pipArray				// <IO> 配列
	, int *pipACnt				// <IO> 配列数
)
{
	int i;
	int liTo = 1;
	int liDCnt = 0;
	for (i = 1; i < *pipACnt; i++) {
		if (pipArray[i] != pipArray[liTo - 1]) {
			pipArray[liTo] = pipArray[i];
			liTo++;
		}
		else {
			liDCnt++;
		}
	}

	*pipACnt -= liDCnt;

	return 0;
}

// セグメントツリー - 子の開始位置 - セット
int
fSegTSetCSNo(
	int piCnt					// <I> 子データ数
)
{
	siSCNo = 1;
	while (siSCNo < piCnt) {
		siSCNo *= 2;
	}

	return 0;
}

// セグメントツリー - 更新
int
fSegTUpRngMain(
	int piUpS					// <I> 更新範囲 - 開始 0～
	, int piUpE					// <I> 更新範囲 - 終了 0～
	, int piUpVal				// <I> 更新値
	, int piNNo					// <I> 現在位置 1～
	, int piNowS				// <I> 現在範囲 - 開始 0～
	, int piNowE				// <I> 現在範囲 - 終了 0～
)
{
	// 範囲外チェック
	if (piUpE < piNowS || piNowE < piUpS) {
		return 0;
	}

	// 範囲内チェック
	if (piUpS <= piNowS && piNowE <= piUpE) {
		si1SegT[piNNo] = piUpVal;							// 更新
		return 0;
	}

	// 更新済みの場合、子に展開しておく
	if (si1SegT[piNNo] != D_SEGT_INI) {
		si1SegT[piNNo * 2] = si1SegT[piNNo];
		si1SegT[piNNo * 2 + 1] = si1SegT[piNNo];
		si1SegT[piNNo] = D_SEGT_INI;						// 自分を初期化
	}

	// 範囲の半分
	int liHalf = (piNowE - piNowS + 1) / 2;

	// 両側の子へ
	fSegTUpRngMain(piUpS, piUpE, piUpVal, piNNo * 2, piNowS, piNowS + liHalf - 1);
	fSegTUpRngMain(piUpS, piUpE, piUpVal, piNNo * 2 + 1, piNowE - liHalf + 1, piNowE);

	return 0;
}
int
fSegTUpRng(
	int piUpS					// <I> 更新範囲 - 開始 0～
	, int piUpE					// <I> 更新範囲 - 終了 0～
	, int piUpVal				// <I> 更新値
)
{
	return fSegTUpRngMain(piUpS, piUpE, piUpVal, 1, 0, siSCNo - 1);
}

// セグメントツリー - 取得
int
fSegTGetOne(
	int piGNo					// <I> 取得位置 0～
)
{
	int liRet;

	// 対象位置
	piGNo += siSCNo;

	// 初期値
	liRet = si1SegT[piGNo];

	// 親に値があれば更新
	while (piGNo > 1) {
		piGNo /= 2;								// 上位へ
		if (si1SegT[piGNo] != D_SEGT_INI) {		// 更新済み
			liRet = si1SegT[piGNo];
		}
	}

	return liRet;
}

// 検索(値の重複不可)
// 戻り値：[>=0]配列番号 [-1]なし
int
fBSrh(
	int piVal					// <I> 値
	, int *pipArray				// <I> 配列
	, int piACnt				// <I> 配列数
)
{
	// 初期範囲
	int liSNo = 0;
	int liENo = piACnt - 1;

	// 検索
	while (1) {

		// 中間位置
		int liMNo = (liSNo + liENo) / 2;

		// 一致チェック
		if (piVal == pipArray[liMNo]) {
			return liMNo;
		}

		// 範囲を絞る
		if (piVal < pipArray[liMNo]) {				// 左側へ
			liENo = liMNo - 1;
		}
		else {										// 右側へ
			liSNo = liMNo + 1;
		}

		// 範囲チェック
		if (liSNo > liENo) {
			return -1;
		}
	}

	return -1;
}

// 実行メイン
int
fMain(
)
{
	int i;
	char lc1Buf[1024];

	// 工事数・人数・時間数 - 取得
	fgets(lc1Buf, sizeof(lc1Buf), szpFpI);
	sscanf(lc1Buf, "%d%d", &siCCnt, &siHCnt);
	siTCnt = siCCnt * 2 + siHCnt;

	// 工事 - 取得
	for (i = 0; i < siCCnt; i++) {
		fgets(lc1Buf, sizeof(lc1Buf), szpFpI);
		sscanf(lc1Buf, "%d%d%d", &sz1Cons[i].miTimeS, &sz1Cons[i].miTimeE, &sz1Cons[i].miPos);
		sz1Cons[i].miTimeS -= sz1Cons[i].miPos;
		sz1Cons[i].miTimeE -= sz1Cons[i].miPos + 1;

		// 時間 - セット
		si1Time[i * 2] = sz1Cons[i].miTimeS;
		si1Time[i * 2 + 1] = sz1Cons[i].miTimeE;
	}

	// 工事 - ソート
	qsort(sz1Cons, siCCnt, sizeof(Cons), fSortFncPd);

	// 出発時間[人] - 取得
	for (i = 0; i < siHCnt; i++) {
		fgets(lc1Buf, sizeof(lc1Buf), szpFpI);
		sscanf(lc1Buf, "%d", &si1Hum[i]);

		// 時間 - セット
		si1Time[siCCnt * 2 + i] = si1Hum[i];
	}

	// 時間 - ソート
	qsort(si1Time, siTCnt, sizeof(int), fSortFncIu);

	// 時間 - 重複カット
	fCutDpl(si1Time, &siTCnt);

	// セグメントツリー - 子の開始位置 - セット
	fSegTSetCSNo(siTCnt);

	// セグメントツリー - 初期値
	fSegTUpRng(0, siTCnt - 1, -1);

	// 工事 - セット
	for (i = 0; i < siCCnt; i++) {

		// 対象位置
		int liSNo = fBSrh(sz1Cons[i].miTimeS, si1Time, siTCnt);
		int liENo = fBSrh(sz1Cons[i].miTimeE, si1Time, siTCnt);

		// セグメントツリー - 更新
		fSegTUpRng(liSNo, liENo, sz1Cons[i].miPos);
	}

	// 出力
	for (i = 0; i < siHCnt; i++) {

		// 対象位置
		int liNo = fBSrh(si1Hum[i], si1Time, siTCnt);

		// セグメントツリー - 取得
		int liPos = fSegTGetOne(liNo);

		// 出力
		sprintf(lc1Buf, "%d\n", liPos);
		fOut(lc1Buf);
	}

	return 0;
}

// １回実行
int
fOne(
)
{
	int liRet;
	char lc1Buf[1024];

	// 入力 - セット
#ifdef D_TEST
	sprintf(lc1Buf, ".\\Test\\T%d.txt", siTNo);
	szpFpI = fopen(lc1Buf, "r");
	sprintf(lc1Buf, ".\\Test\\A%d.txt", siTNo);
	szpFpA = fopen(lc1Buf, "r");
	siRes = 0;
#else
	szpFpI = stdin;
#endif

	// 実行メイン
	liRet = fMain();

	// 残データ有無
#ifdef D_TEST
	lc1Buf[0] = '\0';
	fgets(lc1Buf, sizeof(lc1Buf), szpFpA);
	if (strcmp(lc1Buf, "")) {
		siRes = -1;
	}
#endif

	// テストファイルクローズ
#ifdef D_TEST
	fclose(szpFpI);
	fclose(szpFpA);
#endif

	// テスト結果
#ifdef D_TEST
	if (siRes == 0) {
		printf("OK %d\n", siTNo);
	}
	else {
		printf("NG %d\n", siTNo);
	}
#endif

	return 0;
}

// プログラム開始
int
main()
{

#ifdef D_TEST
	int i;
	for (i = D_TEST_SNO; i <= D_TEST_ENO; i++) {
		siTNo = i;
		fOne();
	}
#else
	fOne();
#endif

	return 0;
}