Problem:
Score : 1100 points

Problem Statement

You are given a directed graph with N vertices and M edges.
The vertices are numbered 1, 2, ..., N, and the edges are numbered 1, 2, ..., M.
Edge i points from Vertex a_i to Vertex b_i.

For each edge, determine whether the reversion of that edge would change the number of the strongly connected components in the graph.

Here, the reversion of Edge i means deleting Edge i and then adding a new edge that points from Vertex b_i to Vertex a_i.

Constraints

2 \leq N \leq 1000

1 \leq M \leq 200,000

1 \leq a_i, b_i \leq N

a_i \neq b_i

If i \neq j, then a_i \neq a_j or b_i \neq b_j.

Input

Input is given from Standard Input in the following format:

N M
a_1 b_1
a_2 b_2
:
a_M b_M

Output

Print M lines. In the i-th line, if the reversion of Edge i would change the number of the strongly connected components in the graph, print diff; if it would not, print same.

Sample Input 1

3 3
1 2
1 3
2 3

Sample Output 1

same
diff
same

The number of the strongly connected components is 3 without reversion of edges, but it will become 1 if Edge 2 is reversed.

Sample Input 2

2 2
1 2
2 1

Sample Output 2

diff
diff

Reversion of an edge may result in multiple edges in the graph.

Sample Input 3

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

Sample Output 3

same
same
same
same
same
diff
diff
diff
diff

Solution in Java8 (OpenJDK 1.8.0) (judge verdict: Time Limit Exceeded)

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;

public class Main implements Runnable {
	public static void main(String[] args) {
		new Thread(null, new Main(), "", Runtime.getRuntime().maxMemory()).start();
	}

	int N;
	int M;
	int[] a;
	int[] b;
	ArrayList<Integer>[] g;
	boolean[][] go;
	int[][] ref;

	void dfs(int cur, int ori) {
		go[ori][cur] = true;
		for (int dst : g[cur]) {
			if (!go[ori][dst])
				dfs(dst, ori);
		}
	}

	void paint_min(int cur, int ori, int col, int[] min) {
		if (min[cur] > col)
			min[cur] = col;
		else
			return;
		for (int dst : g[cur]) {
			if (dst == ori)
				continue;
			paint_min(dst, ori, col, min);
		}
	}

	public void run() {
		Scanner sc = new Scanner(System.in);
		N = sc.nextInt();
		M = sc.nextInt();
		a = new int[M];
		b = new int[M];
		g = new ArrayList[N];
		ref = new int[N][N];
		for (int i = 0; i < N; ++i)
			for (int j = 0; j < N; ++j)
				ref[i][j] = -1;
		for (int i = 0; i < N; ++i)
			g[i] = new ArrayList<>();
		//N<=10^3
		//M<=2*10^5
		for (int i = 0; i < M; ++i) {
			a[i] = sc.nextInt();
			b[i] = sc.nextInt();
			--a[i];
			--b[i];
			g[a[i]].add(b[i]);
			ref[a[i]][b[i]] = i;
		}
		go = new boolean[N][N];
		for (int i = 0; i < N; ++i)
			dfs(i, i);
		boolean[][] go2 = new boolean[N][N];
		int[] tmp = new int[N];
		for (int i = 0; i < N; ++i) {
			Arrays.fill(tmp, g[i].size());
			for (int j = 0; j < g[i].size(); ++j) {
				paint_min(g[i].get(j), i, j, tmp);
			}
			for (int j = 0; j < g[i].size(); ++j) {
				if (tmp[g[i].get(j)] != j) {
					go2[i][g[i].get(j)] = true;
				}
			}
			Arrays.fill(tmp, g[i].size());
			for (int j = g[i].size() - 1; j >= 0; --j) {
				paint_min(g[i].get(j), i, g[i].size() - 1 - j, tmp);
			}
			for (int j = g[i].size() - 1; j >= 0; --j) {
				if (tmp[g[i].get(j)] != g[i].size() - 1 - j) {
					go2[i][g[i].get(j)] = true;
				}
			}
		}
		for (int i = 0; i < M; ++i) {
			if (!go[b[i]][a[i]] && !go2[a[i]][b[i]]) {
				System.out.println("same");
			} else if (go[b[i]][a[i]] && go2[a[i]][b[i]]) {
				System.out.println("same");
			} else {
				System.out.println("diff");
			}
		}
	}

	static void tr(Object... objects) {
		System.out.println(Arrays.deepToString(objects));
	}
}