Problem:
MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], processEscapes: true }});

スケジューラ

あなたはユニークなオペレーティングシステム「ウンズグネ１５」の開発に取り組んでおり、性能を決定付けるスケジューラの設計に頭を悩ませている。スケジューラとは、実行すべき処理をタスクという単位で表現し、それらをどの順序で実行するかを決定するプログラムである。スケジューラはタスクに１から N の番号をつけて管理する。全てのタスクは K 個の属性 f1, f2,..., fK を持ち、各属性にはそれぞれ固有の値が設定されている。ただし、ある２つのタスクについて、対応する属性の値すべてが同じになることはない。

あるタスクには、そのタスクの実行を始める前までに実行を完了していなければならないタスクが与えられることがある。タスクＡがタスクＢの前に完了していなければならないことを「タスクＡ → タスクＢ」と表す。例えば、タスク１ → タスク２、タスク３ → タスク２という関係があれば、タスク２を処理する前にタスク１とタスク３の両方の処理が終わっていなければならない。このような関係をタスク間の依存関係という。ただし、あるタスクから依存関係をたどっていって、そのタスクにたどり着くことはない。

スケジューラは依存関係に従って、実行順序を決定する。しかし、依存関係だけでは順序が一通りに定まらない場合がある。そのような場合は、各タスクが持つ属性の値によって、次に処理するタスクを選択する。

ウンズグネ１５のタスクは属性を複数もつため、すべての属性の値を考慮して実行順序を決定する必要がある。そのために、属性を比較する順番を定める評価順序を用いる。評価順序が最も先の属性を比較し、その属性の値が最も大きいタスクを選択する。そのようなタスクが複数ある場合は、評価順序がその次の属性で比較し、以下同様な手順を繰り返す。例えば、以下の3 つの属性を持つ3 つのタスクについて考える。

タスク＼属性

f1

f2

f3

X

3

3

2

Y

3

2

2

Z

3

1

3

評価順序がf1 f2 f3、f2 f1 f3、または f2 f3 f1 に設定されている場合は、タスクX が選ばれる。また、評価順序が f1 f3 f2、f3 f1 f2、または f3 f2 f1 に設定されている場合はタスクZ が選ばれる。

ウンズグネ１５のスケジューラの特徴は、属性の評価順序が途中で何度でも変更できることである。評価順序は、ある個数のタスクの実行が完了した時点で変更できる。ただし、スケジューラが最初に使う評価順序はあらかじめ決まっている。

各タスクの属性の値、タスクの依存関係、評価順序の変更情報が与えられたとき、タスクを実行する順序を報告するプログラムを作成せよ。

Input

入力は以下の形式で与えられる。

N K
f1,1 f1,2 ... f1,K
f2,1 f2,2 ... f2,K
:
fN,1 fN,2 ... fN,K
D
a1 b1
a2 b2
:
aD bD
e0,1 e0,2 ... e0,K
R
m1 e1,1 e1,2 ...… e1,K
m2 e2,1 e2,2 ...… e2,K
:
mR eR,1 eR,2 ...… eR,K

１行目に、タスクの数 N (2 ≤ N ≤ 50000) と、各タスクが持つ属性の数 K (1 ≤ K ≤ 4) が与えられる。続く N 行に、タスク i が持つ属性の値 fi,j (1 ≤ fi,j ≤ 100000) が与えられる。続く１行に、依存関係の個数 D (0 ≤ D ≤ 200000) が与えられる。続く D 行に依存関係 ai → bi (1 ≤ ai, bi ≤ N) が与えられる。

続く１行に、最初の評価順序 e0,j (1 ≤ e0,j ≤ K) が与えられる。続く１行に、評価順序の変更回数 R (0 ≤ R < N) が与えられる。続く R 行に、評価順序の変更情報が与えられる。i 回目の変更情報は、実行が完了したタスクの個数 mi (1 ≤ mi < N) と評価順序 ei,j (1 ≤ ei,j ≤ K) からなり、全部で mi 個のタスクの実行が完了した時点で、評価順序を ei,1, ei,2,... , ei,K に変更することを示す。

評価順序の変更情報は以下の条件を満たす。

ei,1, ei,2,..., ei,K 中に同じ値は２つ以上現れない。

i < j のとき、 mi < mj である。

Output

スケジューラが処理する順番に、タスクの番号を出力する。

Sample Input 1

5 3
1 5 2
3 8 5
1 2 3
5 5 5
4 8 2
0
1 2 3
2
2 2 3 1
4 3 1 2

Sample Output 1

4
5
2
1
3

Sample Input 2

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

Sample Output 2

3
2
5
1
4

Solution in C (judge verdict: Accepted)

// AOJ 0331 Scheduler
// 2018.2.18 bal4u

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef long long ll;
#define QSIZE 50000

#define PARENT(i) ((i)>>1)
#define LEFT(i)   ((i)<<1)
#define RIGHT(i)  (((i)<<1)+1)

typedef struct { int id; ll k1; int k2; } QUE;
QUE que[24][QSIZE+5];
int qsize[24];

void max_heapify(int qid, int i)
{
	int l, r, max;
	QUE qt;
	l = LEFT(i), r = RIGHT(i);
	if (l < qsize[qid] && (que[qid][l].k1 > que[qid][i].k1 ||
		que[qid][l].k1 == que[qid][i].k1 && que[qid][l].k2 > que[qid][i].k2)) max = l; else max = i;
	if (r < qsize[qid] && (que[qid][r].k1 > que[qid][max].k1 ||
		que[qid][r].k1 == que[qid][max].k1 && que[qid][r].k2 > que[qid][max].k2)) max = r;
	if (max != i) {
		qt = que[qid][i], que[qid][i] = que[qid][max], que[qid][max] = qt;
		max_heapify(qid, max);
	}
}

int deq(int qid)
{
	int id = que[qid][0].id;
//	if (qsize == 0) return 0;
	que[qid][0] = que[qid][--qsize[qid]];
	max_heapify(qid, 0);
	return id;
}

void enq(int qid, int id, ll k1, int k2)
{
	int i, max;
	QUE qt;

	i = qsize[qid]++;
	que[qid][i].id = id, que[qid][i].k1 = k1, que[qid][i].k2 = k2;
	while (i > 0 && (que[qid][max = PARENT(i)].k1 < que[qid][i].k1 ||
		que[qid][max].k1 == que[qid][i].k1 && que[qid][max].k2 < que[qid][i].k2)) {
		qt = que[qid][i]; que[qid][i] = que[qid][max], que[qid][max] = qt;
		i = max;
	}
}

#define MAX 50002

int N, K;
int sz[5] = {1,1,2,6,24};
int q[MAX], top, end; 		// for Topological Sort
int f[MAX][4];
int *to[MAX], hi[MAX], cnt[MAX];
char e[MAX][4]; int m[50002];
char mk[MAX];
int ans[MAX];
char ord[4][4][4][4], idx[24][4];

//#define getchar_unlocked()  getchar()
int in()
{
	int n = 0;
	int c = getchar_unlocked();
	do n = (n<<3)+(n<<1) + (c & 0xf), c = getchar_unlocked();
	while (c >= '0');
	return n;
}

void genperm()
{
	int k, t, th;
	char c[4], *pc, *q;
	char p[4] = {1,1,1,1};

	q = p, pc = c;
	for (k = 1; k <= K; ) *q++ = *pc++ = k++;
	k = 1, pc = c, th = 0;
	do {
		t = *(p + k);
		*(p + k) = *(q = p + ((k & 1)? *pc: 0));
		*q = t;

ord[p[0]-1][p[1]-1][p[2]-1][p[3]-1] = th;
idx[th][0] = p[0]-1, idx[th][1] = p[1]-1;
idx[th][2] = p[2]-1, idx[th][3] = p[3]-1;

		th++;
		k = 1, pc = c;
		while(*pc == 0)	*pc++ = k++;
		(*pc)--;
	} while (k < K);
}

int main() 
{
	int D, R, i, j, k, a, b;
	int done, qid;
	ll k1; int k2;

	N = in(), K = in();
	genperm();
	for (i = 0; i < N; i++) for (j = 0; j < K; j++) f[i][j] = in();

	D = in(); if (D > 0) {
		int *memo = malloc(D << 3), j = 0;
		for (i = 0; i < D; i++) {
			memo[j++] = a = in()-1, memo[j++] = b = in()-1;
			hi[a]++;
		}
		for (i = 0; i < N; i++) if (hi[i] > 0) to[i] = malloc(hi[i] << 2);
		memset(hi, 0, N << 2);
		j = 0; while (D--) {
			a = memo[j++], b = memo[j++];
			to[a][hi[a]++] = b;
			cnt[b]++;
		}
		free(memo);
	}

	for (j = 0; j < K; j++) e[0][j] = in()-1;
	R = in();
	for (i = 1; i <= R; i++) {
		m[i-1] = in();
		for (j = 0; j < K; j++) e[i][j] = in()-1;
	}
	m[i-1] = N;

	done = 0, k = 0, top = end = 0, qid = ord[e[0][0]][e[0][1]][e[0][2]][e[0][3]];
    for (a = 0; a < N; a++) if (!cnt[a]) q[end++] = a;

	while (done < N) {
		while (top < end) {
			a = q[top++];
			k2 = 0;
			for (i = 0; i < sz[K]; i++) {
			                k1 =              f[a][idx[i][0]];
				if (K >= 2) k1 = (k1 << 17) | f[a][idx[i][1]];
				if (K >= 3) k1 = (k1 << 17) | f[a][idx[i][2]];
				if (K == 4) k2 =              f[a][idx[i][3]];
				enq(i, a, k1, k2);
			}
		}

		if (done >= m[k]) k++, qid = ord[e[k][0]][e[k][1]][e[k][2]][e[k][3]];
		do a = deq(qid); while (mk[a]);
		mk[a] = 1;
		ans[done++] = a;

		for (i = 0; i < hi[a]; i++) {
			b = to[a][i]; if (--cnt[b] == 0) q[end++] = b;
		}
    }
	for (i = 0; i < N; i++) printf("%d\n", ans[i]+1);
	return 0;
}