import core.bitop;
import std.algorithm;
import std.array;
import std.bitmanip;
import std.container;
import std.conv;
import std.functional;
import std.math;
import std.numeric;
import std.range;
import std.stdio;
import std.string;
import std.typecons;
import std.range.interfaces;

void main()
{
    bool isBinOp(string op) { return ["AND", "OR", "XOR"].canFind(op); }

    debug { isBinOp("AND").writeln; }

    struct node {
        int id;
        string op;
        bool value;
        int le, r;
        bool flip;
    }

    int n;
    readf("%s", &n);
    readln;

    auto arr = new node[] (n+1);

    foreach (i; 1 .. n+1) {
        auto vals = readln.chomp.split;
        arr[i].id = i;
        arr[i].op = vals[0];
        if (arr[i].op == "IN") {
            arr[i].value = cast(bool) vals[1].to!int;
            continue;
        }

        arr[i].le = vals[1].to!int;
        if (isBinOp(arr[i].op)) arr[i].r = vals[2].to!int;
    }

    bool dfsUp(int v) {
        if (arr[v].op == "NOT") {
            arr[v].value = ! dfsUp(arr[v].le);
        } else if (isBinOp(arr[v].op)) {
            bool leftVal = dfsUp(arr[v].le);
            bool rightVal = dfsUp(arr[v].r);

            if (arr[v].op == "AND") arr[v].value = leftVal && rightVal;
            if (arr[v].op == "XOR") arr[v].value = leftVal ^ rightVal;
            if (arr[v].op == "OR") arr[v].value = leftVal || rightVal;
        }

        return arr[v].value;
    }

    dfsUp(1);

    debug { arr.each!writeln; }

    void dfsDown(int v) {
        if (arr[v].op == "IN") {
            arr[v].flip = true;
            return;
        }

        if (arr[v].op == "NOT") {
            dfsDown(arr[v].le);
            return;
        }

        bool le = arr[arr[v].le].value, r = arr[arr[v].r].value;
        if (arr[v].op == "AND") {
            if (r) {
                dfsDown(arr[v].le);
            }
            if (le) {
                dfsDown(arr[v].r);
            }

            return;
        }

        if (arr[v].op == "OR") {
            if (!r) {
                dfsDown(arr[v].le);
            }
            if (!le) {
                dfsDown(arr[v].r);
            }
            return;
        }

        //XOR
        dfsDown(arr[v].le);
        dfsDown(arr[v].r);
    }

    dfsDown(1);

    debug { arr.filter!(e => e.op == "IN").map!(e => e.flip).each!writeln; }

    auto ans = arr.filter!(e => e.op == "IN").map!(e => arr[1].value ^ e.flip);

    ans.map!(x => x ? '1' : '0').writeln;
}

import std.stdio, std.array, std.string, std.conv, std.algorithm;
import std.typecons, std.range, std.random, std.math, std.container;
import std.numeric, std.bigint, core.bitop, std.bitmanip;

void main() {
    enum OP {IN, NOT, AND, OR, XOR};
    auto N = readln.chomp.to!int;
    auto G = new int[][](N, 2);
    auto P = new int[](N);
    auto B = new bool[](N);
    auto V = new bool[](N);
    auto ops = new OP[](N);

    foreach (i; 0..N) {
        auto s = readln.split;
        string op = s[0];
        foreach (j; 1..s.length) {
            int a = s[j].to!int - 1;
            G[i][j-1] = a;
            if (op != "IN")
                P[a] = i;
        }

        if (op == "IN") {
            ops[i] = OP.IN;
            B[i] = s[1] == "1";
        } else if (op == "NOT") {
            ops[i] = OP.NOT;
        } else if (op == "AND") {
            ops[i] = OP.AND;
        } else if (op == "OR") {
            ops[i] = OP.OR;
        } else {
            ops[i] = OP.XOR;
        }
    }

    bool operate(int n) {
        bool a = G[n][0] >= 0 ? B[G[n][0]] : 0;
        bool b = G[n][1] >= 0 ? B[G[n][1]] : 0;
        if (ops[n] == OP.IN) {
            return B[n];
        } else if (ops[n] == OP.NOT) {
            return !a;
        } else if (ops[n] == OP.AND) {
            return a & b;
        } else if (ops[n] == OP.OR) {
            return a | b;
        } else if (ops[n] == OP.XOR) {
            return a ^ b;
        }
        return 0;
    }

    void init(int n) {
        if (ops[n] == OP.IN) {
            return;
        } else if (ops[n] == OP.NOT) {
            int a = G[n][0];
            init(a);
        } else {
            int a = G[n][0];
            int b = G[n][1];
            init(a);
            init(b);
        }
        B[n] = operate(n);
    }

    void dfs(int n, bool valid) {
        V[n] = valid;
        int a = G[n][0];
        int b = G[n][1];
        if (ops[n] == OP.NOT) {
            dfs(a, valid);
        } else if (ops[n] == OP.AND) {
            if (B[a] && B[b]) {
                dfs(a, valid);
                dfs(b, valid);
            } else if (B[a] && !B[b]) {
                dfs(a, false);
                dfs(b, valid);
            } else if (!B[a] && B[b]) {
                dfs(a, valid);
                dfs(b, false);
            } else {
                dfs(a, false);
                dfs(b, false);
            }
        } else if (ops[n] == OP.OR) {
            if (B[a] && B[b]) {
                dfs(a, false);
                dfs(b, false);
            } else if (B[a] && !B[b]) {
                dfs(a, valid);
                dfs(b, false);
            } else if (!B[a] && B[b]) {
                dfs(a, false);
                dfs(b, valid);
            } else {
                dfs(a, valid);
                dfs(b, valid);
            }
        } else if (ops[n] == OP.XOR) {
            dfs(a, valid);
            dfs(b, valid);
        }
    }

    init(0);
    dfs(0, true);
    N.iota.filter!(i => ops[i] == OP.IN).map!(i => V[i] ? !B[0] : B[0]).map!(i => i.to!int.to!string).join("").writeln;
}

import std.algorithm, std.conv, std.range, std.stdio;
struct C {
	int t, l, r, v;
	int [] h;
}

void main () {
	int n;
	readf (" %s ", &n);
	auto c = new C [n];
	foreach (i, ref x; c) with (x) {
		auto z = readln.split;
		t = z[0][0];
		l = r = -1;
		if (t == 'I') {
			v = z[1].to!int;
			h ~= i;
		} else {
			l = z[1].to!int - 1;
			if (z.length > 2) r = z[2].to!int - 1;
		}
	}

	auto m (int a, int b) {
		if (c[a].h.length < c[b].h.length) swap (a, b);
		return (c[a].h ~= c[b].h);
	}

	void f (int u) {
		if (u < 0) return;
		with (c[u]) {
			f (l);
			f (r);
			if (t == 'I') return;
			if (t == 'N') {
				v = !c[l].v;
				h = c[l].h;
				return;
			}
			if (t == 'X') {
				v = c[l].v ^ c[r].v;
				h = m (l, r);
				return;
			}
			int w = c[l].v * 2 + c[r].v;
			v = w == 3;
			if (t == 'O') {
				w = 3 - w;
				v = w != 3;
			}
			h = w == 0 ? null : w == 1 ? c[l].h : w == 2 ? c[r].h : m (l, r);
		}
	}

	f (0);
	auto r = new int [n];
	r[] = c[0].v;
	foreach (i; c[0].h) r[i] ^= 1;
	writefln ("%(%s%)", n.iota.filter !(i => c[i].t == 'I').map !(i => r[i]));
}

import std.algorithm;
import std.conv;
import std.range;
import std.stdio;
import std.string;
import std.typecons;

immutable int NA = -1;

void main ()
{
	int n;
	while (readf (" %s", &n) > 0)
	{
		alias Command = Tuple !(string, q{name}, int, q{left},
		    int, q{right}, int, q{value}, int [], q{inputs});
		auto commands = new Command [n];

		readln;
		foreach (i, ref command; commands)
		{
			with (command)
			{
				auto t = readln.split;
				name = t[0];
				left = NA;
				right = NA;
				if (name == "IN")
				{
					value = t[1].to !(int);
					inputs ~= i;
				}
				else
				{
					left = t[1].to !(int) - 1;
					if (t.length > 2)
					{
						right = t[2].to !(int) - 1;
					}
				}
			}
		}

		int [] mergeInputs (int one, int two)
		{
			if (commands[one].inputs.length <
			    commands[two].inputs.length)
			{
				swap (one, two);
			}
			int [] res = commands[one].inputs;
			res ~= commands[two].inputs;
			return res;
		}

		void recur (int v)
		{
			with (commands[v])
			{
				if (left != NA)
				{
					recur (left);
				}
				if (right != NA)
				{
					recur (right);
				}
				if (name == "IN")
				{
				}
				else if (name == "NOT")
				{
					value = !commands[left].value;
					inputs = commands[left].inputs;
				}
				else if (name == "XOR")
				{
					value = commands[left].value ^
					    commands[right].value;
					inputs = mergeInputs (left, right);
				}
				else if (name == "AND")
				{
					auto w0 = commands[left].value;
					auto w1 = commands[right].value;
					value = w0 & w1;
					if (!w0 && !w1)
					{
						inputs = null;
					}
					if (!w0 && w1)
					{
						inputs = commands[left].inputs;
					}
					if (w0 && !w1)
					{
						inputs = commands[right].inputs;
					}
					if (w0 && w1)
					{
						inputs = mergeInputs (left, right);
					}
					return;
				}
				else if (name == "OR")
				{
					auto w0 = commands[left].value;
					auto w1 = commands[right].value;
					value = w0 | w1;
					if (w0 && w1)
					{
						inputs = null;
					}
					if (w0 && !w1)
					{
						inputs = commands[left].inputs;
					}
					if (!w0 && w1)
					{
						inputs = commands[right].inputs;
					}
					if (!w0 && !w1)
					{
						inputs = mergeInputs (left, right);
					}
					return;
				}
				else
				{
					assert (false);
				}
			}
		}

		recur (0);

		auto res = new int [n];
		res[] = commands[0].value;
		foreach (i; commands[0].inputs)
		{
			res[i] ^= 1;
		}

		writefln ("%(%s%)", n.iota
		    .filter !(i => commands[i].name == "IN")
		    .map !(i => res[i]));
	}
}

import std.algorithm, std.conv, std.range, std.stdio;
immutable int NA = -1;
struct Cmd {
	string name;
	int left, right, value;
	int [] inputs;
}

void main () {
	int n;
	readf (" %s ", &n);
	auto cmds = new Cmd [n];
	foreach (i, ref cmd; cmds) with (cmd) {
		auto t = readln.split;
		name = t[0];
		left = NA;
		right = NA;
		if (name == "IN") {
			value = t[1].to!int;
			inputs ~= i;
		} else {
			left = t[1].to!int - 1;
			if (t.length > 2)
				right = t[2].to!int - 1;
		}
	}

	auto mergeInputs (int one, int two) {
		if (cmds[one].inputs.length < cmds[two].inputs.length)
			swap (one, two);
		auto res = cmds[one].inputs;
		res.assumeSafeAppend ();
		res ~= cmds[two].inputs;
		return res;
	}

	void recur (int v) {
		if (v == NA)
			return;
		with (cmds[v]) {
			recur (left);
			recur (right);
			if (name == "IN")
				return;
			if (name == "NOT") {
				value = !cmds[left].value;
				inputs = cmds[left].inputs;
				return;
			}
			if (name == "XOR") {
				value = cmds[left].value ^ cmds[right].value;
				inputs = mergeInputs (left, right);
				return;
			}
			int w = cmds[left].value * 2 + cmds[right].value;
			value = w == 3;
			if (name == "OR") {
				w = 3 - w;
				value = w != 3;
			}
			inputs = w == 0 ? null : w == 1 ? cmds[left].inputs : w == 2 ? cmds[right].inputs : mergeInputs (left, right);
		}
	}

	recur (0);
	auto res = new int [n];
	res[] = cmds[0].value;
	foreach (i; cmds[0].inputs)
		res[i] ^= 1;
	writefln ("%(%s%)", n.iota.filter !(i => cmds[i].name == "IN").map !(i => res[i]));
}

import std.stdio;
import std.uni;
import std.conv;
import std.container;
import std.functional;
import std.algorithm;
import std.array;
import std.typecons;
import std.range;
import std.numeric;
import std.traits;
import std.variant;
import std.concurrency;

void main(string[] args)
{
  auto n = next!int;
  struct NodeInfo
  {
    enum Type
      {
	and, or, xor, not, input
      };
    Type type;
    int o1, o2;
    int value;
  }
  auto nodes = new NodeInfo[](n);
 nodeInput:foreach(i; 0 .. n)
    {
      auto typeString = next!string;
      final switch(typeString)
	{
	case "AND":
	  nodes[i].type = NodeInfo.Type.and;
	  break;
	case "OR":
	  nodes[i].type = NodeInfo.Type.or;
	  break;
	case "XOR":
	  nodes[i].type = NodeInfo.Type.xor;
	  break;
	case "NOT":
	  nodes[i].type = NodeInfo.Type.not;
	  nodes[i].o1 = next!int - 1;
	  continue nodeInput;
	case "IN":
	  nodes[i].type = NodeInfo.Type.input;
	  nodes[i].value = next!int;
	  continue nodeInput;
	}
      nodes[i].o1 = next!int - 1;
      nodes[i].o2 = next!int - 1;
    }
  auto valueOf = new int[](n);
  int calcValue(int i)
  {
    auto node = nodes[i];
    int res = -1;
    final switch(node.type)
      {
      case NodeInfo.Type.and:
	res = calcValue(node.o1) & calcValue(node.o2);
	break;
      case NodeInfo.Type.or:
	res = calcValue(node.o1) | calcValue(node.o2);
	break;
      case NodeInfo.Type.xor:
	res = calcValue(node.o1) ^ calcValue(node.o2);
	break;
      case NodeInfo.Type.not:
	res = !calcValue(node.o1);
	break;
      case NodeInfo.Type.input:
	res = node.value;
	break;
      }
    valueOf[i] = res;
    return res;
  }
  calcValue(0);
  debug foreach(i; 0 .. n)
    {
      writeln(i + 1, ": ", valueOf[i]);
    }
  auto res = new int[](n);
  res[] = valueOf[0];
  void change(int i)
  {
    auto node = nodes[i];
    auto value = valueOf[i];
    final switch(node.type)
      {
      case NodeInfo.Type.and:
	if (value == 1)
	  {
	    change(node.o1);
	    change(node.o2);
	    return;
	  }
	if (!valueOf[node.o1] && !valueOf[node.o2]) return;
	if (!valueOf[node.o1]) return change(node.o1);
	assert(!valueOf[node.o2]);
	return change(node.o2);
      case NodeInfo.Type.or:
	if (value == 0)
	  {
	    change(node.o1);
	    change(node.o2);
	    return;
	  }
	if (valueOf[node.o1] && valueOf[node.o2]) return;
	if (valueOf[node.o1]) return change(node.o1);
	assert(valueOf[node.o2]);
	return change(node.o2);
      case NodeInfo.Type.xor:
	change(node.o1);
	return change(node.o2);
      case NodeInfo.Type.not:
	return change(node.o1);
      case NodeInfo.Type.input:
	res[i] = !res[i];
      }
  }
  change(0);

  foreach(i; 0 .. n)
    {
      if (nodes[i].type == NodeInfo.Type.input)
	{
	  write(res[i]);
	}
    }
  writeln;
}

static this()
{
  popChar;
}

struct Any(T)
{
  static auto read()
  {
    static if (is(T == char))
      {
	auto res = frontChar;
	popChar;
	return res;
      }
  }
}

struct Unsigned(T)
{
  auto read()
  {
    auto res = T(0);
    while(!frontChar.isDigit) popChar;
    do
      {
	res = res * T(10) + T(frontChar - '0');
	popChar;
      }
    while(frontChar.isDigit);
    return res;
  }
}

struct Matrix(T, alias rows, alias cols)
{
  T[][] _cell;
  alias _cell this;
  // Ring constructor
  this(int n)
  {
    final switch(n)
      {
      case 0:
	_cell = new T[][](rows, cols);
	break;
      case 1:
	debug assert(rows == cols);
	_cell = new T[][](rows, cols);
	foreach(i; 0 .. rows)
	  _cell[i][i] = T(1);
	break;
      }
  }
  // Copy constructor
  this(Matrix!(T, rows, cols) other)
  {
    _cell = new T[][](rows, cols);
    foreach(i; 0 .. rows)
      _cell[i][] = other[i][];
  }
  auto opBinary(string op)(Matrix!(T, rows, cols) other)
       if (op == "+" || op == "-")
	 {
	   auto res = Matrix!(T, rows, cols)(0);
	   foreach(i; 0 .. rows)
	     foreach(j; 0 .. cols)
	       res[i][j] = mixin(q{this[i][j]}, op, q{other[i][j]});
	   return res;
	 }
  auto opBinary(string op, alias otherRows, alias otherCols)(Matrix!(T, otherRows, otherCols) other)
       if (op == "*")
	 {
	   debug assert(cols == otherRows);
	   auto res = Matrix!(T, rows, otherCols)(0);
	   foreach(i; 0 .. rows)
	     foreach(k; 0 .. cols)
	       foreach(j; 0 .. otherCols)
		 res[i][j] += this[i][k] * other[k][j];
	   return res;
	 }
  ref auto opOpAssign(string op)(Matrix!(T, rows, cols) other)
  {
    static if (op == "*")
      {
	debug assert(rows == cols);
	alias n = rows;
	auto res = Matrix!(T, n, n)(0);
	T factor;
	foreach(i; 0 .. n)
	  foreach(k; 0 .. n)
	    foreach(j; 0 .. n)
	      res[i][j] += this[i][k] * other[k][j];
	foreach(i; 0 .. n)
	  this[i][] = res[i][];
      }
    else
      {
	foreach(i; 0 .. rows)
	  foreach(j; 0 .. cols)
	    mixin(q{this[i][j] }, text(op, q{=}), q{ other[i][j];});
      }
    return this;
  }
  mixin powMethod;
}

struct Mod(T, alias mod)
{
  alias This = Mod!(T, mod);
  T _rep;
  this(T t)
  {
    _rep = t % mod;
    if (_rep < 0) _rep += mod;
  }
  static auto plain(T t)
  {
    auto res = Mod!(T, mod)();
    res._rep = t;
    return res;
  }
  static auto fromPositive(T t)
  {
    pragma(inline, true);
    return Mod!(T, mod).plain(t % mod);
  }
  static auto fromNegative(T t)
  {
    pragma(inline, true);
    return Mod!(T, mod).plain(t % mod + mod);
  }
  string toString()
  {
    return to!string(_rep);
  }
  debug invariant
  {
    assert(_rep >= 0 && _rep < mod);
  }
  auto opBinary(string op)(This b)
  {
    static if (op == "+")
      {
	T resrep = _rep + b._rep;
	if (resrep >= mod) resrep -= mod;
	return This.plain(resrep);
      }
    else static if (op == "-")
      {
	T resrep = _rep - b._rep;
	if (resrep < 0) resrep += mod;
	return This.plain(resrep);
      }
    else static if (op == "*")
      {
	return This.fromPositive(_rep * b._rep);
      }
  }
  auto opOpAssign(string op)(This b)
  {
    mixin(q{_rep }, text(op, "="), q{b._rep;});
    static if (op == "+")
      {
	if (_rep >= mod) _rep -= mod;
      }
    else static if (op == "-")
      {
	if (_rep < 0) _rep += mod;
      }
    else static if (op == "*")
      {
	_rep %= mod;
      }
    return this;
  }

  auto opBinary(string op)(long exp)
       if (op == "^^")
	 {
	   return pow(exp);
	 }
  mixin powMethod;
}

mixin template powMethod()
{
  auto pow(this ThisType)(long exp)
    {
      auto res = ThisType(1);
      auto pow = ThisType(this);
      while(exp)
	{
	  if (exp & 1) res *= pow;
	  pow *= pow;
	  exp >>= 1;
	}
      return res;
    }
}
// INPUT
char frontChar;
void popChar()
{
  import core.stdc.stdio;
  frontChar = cast(char) getchar;
  if (feof(stdin)) frontChar = ' ';
}
auto makeArray(T, S...)(S s)
{
  enum brackets = () {
    string res;
    foreach(i; 0 .. s.length)
      res ~= "[]";
    return res;
  } ();
  mixin(q{alias Type = T}, brackets, q{;});
  return new Type(s);
}
template isNumberLike(T)
{
  enum isNumberLike = is(typeof((){T test; test = test + test * test; test *= test;}()));
}
void popWhite()
{
  import std.ascii;
  while (frontChar.isWhite) popChar;
}
void print(T...)(T t)
{
  static foreach(ti; t)
    {
      static if (is(typeof(ti) == string))
	{
	  write(ti, " ");
	}
      else static if (isArray!(typeof(ti)))
	{
	  foreach(e; ti) print(e);
	}
      else static if (isTuple!(typeof(ti)))
	{
	  static foreach(i; ti.length) writesp(ti[i]);
	}
      else
	{
	  write(ti, " ");
	}
    }
}
void println(T...)(T t)
{
  static if (t.length == 0)
    writeln;
  static foreach(ti; t)
    {
      print(ti);
      writeln;
    }
}
auto next(alias T, S...)(S s)
{
  pragma(inline, true);
  static if (s.length > 0)
    {
      auto res = makeArray!(typeof(next!T()))(s);
      S t;
      enum loops = () {
	string res;
	foreach(i; 0 .. s.length)
	  {
	    auto ti = text(q{t[}, i, q{]});
	    res ~= text(q{for(}, ti, q{ = 0;}, ti , q{ < s[}, i, q{];}, ti, q{++)});
	  }
	return res;
      } ();
      enum indexing = () {
	string res = "res";
	foreach(i; 0 .. s.length)
	  res ~= text(q{[t[}, i, q{]]});
	return res;
      } ();
      mixin(loops, indexing, q{ = next!T;});
      return res;
    }
  else
    {
      static if (isNumberLike!T)
	{
	  import std.ascii: isDigit;
	  T res;
	  while(frontChar.isWhite) popChar;
	  T multiplier = T(1);
	  if (frontChar == '-')
	    {
	      multiplier = T(-1);
	      popChar;
	    }
	  else if (frontChar == '+')
	    {
	      popChar;
	    }
	  debug assert(frontChar.isDigit);
	  do
	    {
	      res = res * T(10) + T(frontChar - '0');
	      popChar;
	    }
	  while(frontChar.isDigit);
	  return multiplier * res;
	}
      else static if (is(T == string))
	{
	  import std.ascii: isWhite;
	  string res;
	  while(frontChar.isWhite)
	    popChar;
	  while(!frontChar.isWhite)
	    {
	      res ~= frontChar;
	      popChar;
	    }
	  return res;
	}
      else static if (is(T == char))
	{
	  while(frontChar.isWhite) popChar;
	  auto res = frontChar;
	  popChar;
	  return res;
	}
      else
	{
	  return T.read;
	}
    }
}

import std.stdio, std.array, std.string, std.conv, std.algorithm;
import std.typecons, std.range, std.random, std.math, std.container;
import std.numeric, std.bigint, core.bitop, std.bitmanip;

void main() {
    enum OP {IN, NOT, AND, OR, XOR};
    auto N = readln.chomp.to!int;
    auto G = new int[][](N, 2);
    auto P = new int[](N);
    auto ops = new OP[](N);
    auto bits = new bool[](N);
    auto not = new bool[](N);

    foreach (i; 0..N) {
        auto s = readln.split;
        string op = s[0];
        foreach (j; 1..s.length) {
            int a = s[j].to!int - 1;
            G[i][j-1] = a;
            if (op != "IN")
                P[a] = i;
        }

        if (op == "IN") {
            ops[i] = OP.IN;
            bits[i] = s[1] == "1";
        } else if (op == "NOT") {
            ops[i] = OP.NOT;
            not[i] = true;
        } else if (op == "AND") {
            ops[i] = OP.AND;
        } else if (op == "OR") {
            ops[i] = OP.OR;
        } else {
            ops[i] = OP.XOR;
        }
    }

    void dfs(int n, int pn) {
        if (ops[n] == OP.NOT) {
            int m = G[n][0];
            G[P[n]][pn] = m;
            P[m] = P[n];
            not[m] ^= not[n];
            dfs(m, pn);
        } else if (ops[n] != OP.IN) {
            foreach (i; 0..2) {
                dfs(G[n][i], i);
            }
        }
    }

    bool operate(int n) {
        bool ret;
        bool a = G[n][0] >= 0 ? bits[G[n][0]] : 0;
        bool b = G[n][1] >= 0 ? bits[G[n][1]] : 0;
        if (ops[n] == OP.IN) {
            ret = bits[n];
        } else if (ops[n] == OP.NOT) {
            ret = !a;
        } else if (ops[n] == OP.AND) {
            ret = a & b;
        } else if (ops[n] == OP.OR) {
            ret = a | b;
        } else if (ops[n] == OP.XOR) {
            ret = a ^ b;
        }
        return ret ^ not[n];
    }

    void init(int n) {
        int a = G[n][0];
        int b = G[n][1];
        if (ops[n] == OP.IN) {
            if (not[n]) {
                bits[n] ^= 1;
                not[n] ^= 1;
            }
        } else if (ops[n] == OP.NOT) {
            init(a);
            bits[n] = operate(n);
        } else {
            init(a);
            init(b);
            bits[n] = operate(n);
        }
    }

    void up(int n) {

        bits[n] = operate(n);
        if (n != 0) up(P[n]);
    }

    if (ops[0] == OP.NOT) {
        dfs(G[0][0], 0);
    } else {
        dfs(0, -1);
    }

    bool[] ans;
    init(0);

    foreach (i; 0..N) {
        if (ops[i] != OP.IN)
            continue;
        bits[i] ^= 1;
        up(i);
        ans ~= bits[0];
        bits[i] ^= 1;
        up(i);
    }

    ans.map!(a => a ? "1" : "0").join.writeln;
}

import std.stdio, std.array, std.string, std.conv, std.algorithm;
import std.typecons, std.range, std.random, std.math, std.container;
import std.numeric, std.bigint, core.bitop, std.bitmanip;

void main() {
    enum OP {IN, NOT, AND, OR, XOR};
    auto N = readln.chomp.to!int;
    auto G = new int[][](N, 2);
    auto P = new int[](N);
    auto ops = new OP[](N);
    auto bits = new bool[](N);
    auto not = new bool[](N);

    foreach (i; 0..N) {
        auto s = readln.split;
        string op = s[0];
        foreach (j; 1..s.length) {
            int a = s[j].to!int - 1;
            G[i][j-1] = a;
            if (op != "IN")
                P[a] = i;
        }

        if (op == "IN") {
            ops[i] = OP.IN;
            bits[i] = s[1] == "1";
        } else if (op == "NOT") {
            ops[i] = OP.NOT;
        } else if (op == "AND") {
            ops[i] = OP.AND;
        } else if (op == "OR") {
            ops[i] = OP.OR;
        } else {
            ops[i] = OP.XOR;
        }
    }

    void dfs(int n, int pn) {
        if (ops[n] == OP.NOT) {
            int m = G[n][0];
            G[P[n]][pn] = m;
            P[m] = P[n];
            not[m] ^= not[n];
            dfs(m, pn);
        } else if (ops[n] != OP.IN) {
            foreach (i; 0..2) {
                dfs(G[n][i], i);
            }
        }
    }

    bool operate(int n) {
        bool ret;
        bool a = G[n][0] >= 0 ? bits[G[n][0]] : 0;
        bool b = G[n][1] >= 0 ? bits[G[n][1]] : 0;
        if (ops[n] == OP.IN) {
            ret = bits[n];
        } else if (ops[n] == OP.NOT) {
            ret = !a;
        } else if (ops[n] == OP.AND) {
            ret = a & b;
        } else if (ops[n] == OP.OR) {
            ret = a | b;
        } else if (ops[n] == OP.XOR) {
            ret = a ^ b;
        }
        return ret ^ not[n];
    }

    void init(int n) {
        int a = G[n][0];
        int b = G[n][1];
        if (ops[n] == OP.IN) {
            if (not[n]) {
                bits[n] ^= 1;
                not[n] ^= 1;
            }
        } else if (ops[n] == OP.NOT) {
            init(a);
            bits[n] = operate(n);
        } else {
            init(a);
            init(b);
            bits[n] = operate(n);
        }
    }

    void up(int n) {
        bits[n] = operate(n);
        if (n != 0) up(P[n]);
    }

    if (ops[0] == OP.NOT) {
        dfs(G[0][0], 0);
    } else {
        dfs(0, -1);
    }

    bool[] ans;
    init(0);

    foreach (i; 0..N) {
        if (ops[i] != OP.IN)
            continue;
        bits[i] ^= 1;
        up(i);
        ans ~= bits[0];
        bits[i] ^= 1;
        up(i);
    }

    ans.map!(a => a ? "1" : "0").join.writeln;
}

import std.stdio, std.array, std.string, std.conv, std.algorithm;
import std.typecons, std.range, std.random, std.math, std.container;
import std.numeric, std.bigint, core.bitop, std.bitmanip;

void main() {
    enum OP {IN, NOT, AND, OR, XOR};
    auto N = readln.chomp.to!int;
    auto G = new int[][](N, 2);
    auto P = new int[](N);
    auto ops = new OP[](N);
    auto bits = new bool[](N);
    auto not = new bool[](N);

    foreach (i; 0..N) {
        auto s = readln.split;
        string op = s[0];
        foreach (j; 1..s.length) {
            int a = s[j].to!int - 1;
            G[i][j-1] = a;
            if (op != "IN")
                P[a] = i;
        }

        if (op == "IN") {
            ops[i] = OP.IN;
            bits[i] = s[1] == "1";
        } else if (op == "NOT") {
            ops[i] = OP.NOT;
            not[i] = true;
        } else if (op == "AND") {
            ops[i] = OP.AND;
        } else if (op == "OR") {
            ops[i] = OP.OR;
        } else {
            ops[i] = OP.XOR;
        }
    }

    void dfs(int start) {
        auto stack = new Tuple!(int, int)[](N);
        int p = 0;
        stack[0] = tuple(start, 0);
        while (p >= 0) {
            int n = stack[p][0];
            int pn = stack[p][1];
            --p;
            if (ops[n] == OP.NOT) {
                int m = G[n][0];
                G[P[n]][pn] = m;
                P[m] = P[n];
                not[m] ^= not[n];
                stack[++p] = tuple(m, pn);
            } else if (ops[n] != OP.IN) {
                foreach (i; 0..2) {
                    stack[++p] = tuple(G[n][i], i);
                }
            }
        }
    }

    bool operate(int n) {
        bool ret;
        bool a = G[n][0] >= 0 ? bits[G[n][0]] : 0;
        bool b = G[n][1] >= 0 ? bits[G[n][1]] : 0;
        if (ops[n] == OP.IN) {
            ret = bits[n];
        } else if (ops[n] == OP.NOT) {
            ret = !a;
        } else if (ops[n] == OP.AND) {
            ret = a & b;
        } else if (ops[n] == OP.OR) {
            ret = a | b;
        } else if (ops[n] == OP.XOR) {
            ret = a ^ b;
        }
        return ret ^ not[n];
    }

    void init(int n) {
        int a = G[n][0];
        int b = G[n][1];
        if (ops[n] == OP.IN) {
            if (not[n]) {
                bits[n] ^= 1;
                not[n] ^= 1;
            }
        } else if (ops[n] == OP.NOT) {
            init(a);
            bits[n] = operate(n);
        } else {
            init(a);
            init(b);
            bits[n] = operate(n);
        }
    }

    void up(int n) {
        bits[n] = operate(n);
        if (n != 0) up(P[n]);
    }

    if (ops[0] == OP.NOT) {
        dfs(G[0][0]);
    } else {
        dfs(0);
    }

    bool[] ans;
    init(0);

    foreach (i; 0..N) {
        if (ops[i] != OP.IN)
            continue;
        bits[i] ^= 1;
        up(i);
        ans ~= bits[0];
        bits[i] ^= 1;
        up(i);
    }

    ans.map!(a => a ? "1" : "0").join.writeln;
}

import std.algorithm, std.conv, std.range, std.stdio;
immutable int NA = -1;
struct Cmd {
	string name;
	int left, right, value;
	int [] inputs;
}

void main () {
	int n;
	readf (" %s ", &n);
	auto cmds = new Cmd [n];
	foreach (i, ref cmd; cmds) with (cmd) {
		auto t = readln.split;
		name = t[0];
		left = NA;
		right = NA;
		if (name == "IN") {
			value = t[1].to!int;
			inputs ~= i;
		} else {
			left = t[1].to!int - 1;
			if (t.length > 2)
				right = t[2].to!int - 1;
		}
	}

	auto mergeInputs (int one, int two) {
		if (cmds[one].inputs.length < cmds[two].inputs.length)
			swap (one, two);
		auto res = cmds[one].inputs;
		res.assumeSafeAppend ();
		res ~= cmds[two].inputs;
		return res;
	}

	void recur (int v) {
		if (v == NA)
			return;
		with (cmds[v]) {
			recur (left);
			recur (right);
			if (name == "IN")
				return;
			if (name == "NOT") {
				value = !cmds[left].value;
				inputs = cmds[left].inputs;
				return;
			}
			if (name == "XOR") {
				value = cmds[left].value ^ cmds[right].value;
				inputs = mergeInputs (left, right);
				return;
			}
			int w = cmds[left].value * 2 + cmds[right].value;
			value = w == 3;
			if (name == "OR") {
				w = 3 - w;
				value = w != 0;
			}
			inputs = w == 0 ? null : w == 1 ? cmds[left].inputs : w == 2 ? cmds[right].inputs : mergeInputs (left, right);
		}
	}

	recur (0);
	auto res = new int [n];
	res[] = cmds[0].value;
	foreach (i; cmds[0].inputs)
		res[i] ^= 1;
	writefln ("%(%s%)", n.iota.filter !(i => cmds[i].name == "IN").map !(i => res[i]));
}

import core.bitop;
import std.algorithm;
import std.array;
import std.bitmanip;
import std.container;
import std.conv;
import std.functional;
import std.math;
import std.numeric;
import std.range;
import std.stdio;
import std.string;
import std.typecons;
import std.range.interfaces;

void main()
{
    bool isBinOp(string op) { return ["AND", "OR", "XOR"].canFind(op); }

    debug { isBinOp("AND").writeln; }

    struct node {
        int id;
        string op;
        bool value;
        int le, r;
        bool flip;
    }

    int n;
    readf("%s", &n);
    readln;

    auto arr = new node[] (n+1);

    foreach (i; 1 .. n+1) {
        auto vals = readln.chomp.split;
        arr[i].id = i;
        arr[i].op = vals[0];
        if (arr[i].op == "IN") {
            arr[i].value = cast(bool) vals[1].to!int;
            continue;
        }

        arr[i].le = vals[1].to!int;
        if (isBinOp(arr[i].op)) arr[i].r = vals[2].to!int;
    }

    bool dfsUp(int v) {
        if (arr[v].op == "NOT") {
            arr[v].value = ! dfsUp(arr[v].le);
        } else if (isBinOp(arr[v].op)) {
            bool leftVal = dfsUp(arr[v].le);
            bool rightVal = dfsUp(arr[v].r);

            if (arr[v].op == "AND") arr[v].value = leftVal && rightVal;
            if (arr[v].op == "XOR") arr[v].value = leftVal ^ rightVal;
            if (arr[v].op == "OR") arr[v].value = leftVal || rightVal;
        }

        return arr[v].value;
    }

    dfsUp(1);

    debug { arr.each!writeln; }

    void dfsDown(int v) {
        if (arr[v].op == "IN") {
            arr[v].flip = true;
            return;
        }

        if (arr[v].op == "NOT") {
            dfsDown(arr[v].le);
            return;
        }

        bool le = arr[arr[v].le].value, r = arr[arr[v].r].value;
        if (arr[v].op == "AND") {
            if (le & r) {
                dfsDown(arr[v].le);
                dfsDown(arr[v].r);
            } else if (le) {
                dfsDown(arr[v].r);
            } else if (r) {
                dfsDown(arr[v].le);
            }

            return;
        }

        if (arr[v].op == "OR") {
            if (!(le || r)) {
                dfsDown(arr[v].le);
                dfsDown(arr[v].r);
            } else if (le) {
                dfsDown(arr[v].le);
            } else if (r) {
                dfsDown(arr[v].r);
            }

            return;
        }

        //XOR
        dfsDown(arr[v].le);
        dfsDown(arr[v].r);
    }

    dfsDown(1);

    debug { arr.filter!(e => e.op == "IN").map!(e => e.flip).each!writeln; }

    auto ans = arr.filter!(e => e.op == "IN").map!(e => arr[1].value ^ e.flip);

    ans.map!(x => x ? '1' : '0').writeln;
}


import std.stdio, std.conv, std.functional, std.string;
import std.algorithm, std.array, std.container, std.range, std.typecons;
import std.bigint, std.numeric, std.math, std.random;
import core.bitop;

string FMT_F = "%.10f";

static File _f;
void file_io(string fn) { _f = File(fn, "r"); }
static string[] s_rd;
T _RD(T = long)() { while(!s_rd.length) s_rd = readln.chomp.split; string res = s_rd[0]; s_rd.popFront; return res.to!T; }
T _RD(T = long)(File f) { while(!s_rd.length) s_rd = f.readln.chomp.split; string res = s_rd[0]; s_rd.popFront; return res.to!T; }
T[] _RDA(T = long)(T fix = 0) { auto r = readln.chomp.split.to!(T[]); r[] += fix; return r; }
T[] _RDA(T = long)(File f, T fix = 0) { auto r = f.readln.chomp.split.to!(T[]); r[] += fix; return r; }
T RD(T = long)() { if (_f.isOpen) return _RD!T(_f); else return _RD!T; }
T[] RDA(T = long)(T fix = 0) { if (_f.isOpen)  return _RDA!T(_f, fix); else return _RDA!T(fix); }

size_t[] MAKE_IDX(alias less = "a < b", Range)(Range range) { auto idx = new size_t[](range.length); makeIndex!(less)(range, idx); return idx;}
size_t MIN_POS(alias less = "a < b", Range)(Range range) { auto r = minPos!(less)(range); return range.length - r.length; }

void chmin(T)(ref T x, T y) { x = min(x, y); } void chmax(T)(ref T x, T y) { x = max(x, y); }
bool inside(T)(T x, T b, T e) { return x >= b && x < e; }
T lcm(T)(T x, T y) { return x * (y / gcd(x, y)); }
double euDist(T)(T[] a, T[] b) { auto c = a.dup; c[] -= b[]; c[] *= c[]; return sqrt(cast(double)c.sum); }
double[] rotate(double[] vec, double rad) { return [cos(rad)*vec[0] - sin(rad)*vec[1], sin(rad)*vec[0] + cos(rad)*vec[1]]; }
double norm(double[] vec) { return sqrt(reduce!((a,b)=>a+b*b)(0.0, vec)); }
double dotProd(double[] a, double[] b) { auto r = a.dup; r[] *= b[]; return r.sum; }

//long mod = 10^^9 + 7;
long mod = 998_244_353;
//long mod = 1_000_003;
void moda(ref long x, long y) { x = (x + y) % mod; }
void mods(ref long x, long y) { x = ((x + mod) - (y % mod)) % mod; }
void modm(ref long x, long y) { x = (x * y) % mod; }
void modpow(ref long x, long y) { if (!y) { x = 1; return; } auto t = x; x.modpow(y>>1); x.modm(x); if (y&1) x.modm(t); }
void modd(ref long x, long y) { y.modpow(mod - 2); x.modm(y); }

void main()
{
	auto t = RD!int;
	auto ans = new long[](t);
	foreach (ti; 0..t)
	{
		auto n = RD!int;
		auto k = RD!int;
		auto s = RD!string;

		if (k == 0)
		{
			ans[ti] = 1;
			continue;
		}

		int l, r = n-1;
		bool ok = true;
		while (l < r)
		{
			if (s[l] != s[r])
			{
				ok = false;
				break;
			}
			++l; --r;
		}
		if (ok)
			ans[ti] = 1;
		else
			ans[ti] = 2;
	}

	foreach (e; ans)
		writeln(e);
	stdout.flush;
	debug readln;
}

// cheese-cracker [2022-02-06]

void solve(){
    long n = scan;
    long k = scan;
    auto s = scan!(dchar[]);
    auto rs = s.dup;
    rs.reverse;
    if(s == rs || k == 0){
        writeln(1);
    }else{
        writeln(2);
    }
}

void main(){
    long tests = scan;        // Toggle!
    while(tests--) solve;
}

/*_________________________*That's All Folks!*__________________________*/
import std.stdio, std.range, std.conv, std.typecons, std.algorithm, std.container, std.math, std.numeric;
string[] tk; alias tup = Tuple!(long, long);
T scan(T=long)(){while(!tk.length)tk = readln.split; string a=tk.front; tk.popFront; return a.to!T;}
T[] scanArray(T=long)(){ auto r = readln.split.to!(T[]); return r; }
void show(A...)(A a){ debug{ foreach(t; a){stderr.write(t, "| ");} stderr.writeln; } }


import std.stdio : writef, readf, readln, writeln, writefln;
import std.array : array, split;
import std.algorithm;
import std.conv : to;
import std.range : iota, tee, enumerate;
import std.algorithm.comparison;
import std.container.rbtree : RBT = RedBlackTree;
import std.string : strip;
import core.memory : GC;
import std.typecons : tuple;
import std.math : abs;

alias Tree = RBT!int;

void main() {
  GC.disable();

  uint n;
  readf(" %s", n);

  auto a = new int[n];
  foreach(i; 0 .. n) {
    readf(" %s", a[i]);
  }

  auto aa = a.enumerate.array.sort!"a.value < b.value";
  int k = 1_000_000_009;
  int maxidx = -1;
  int minidx = n+n;
  for(int i = n-1; i>=0; i--) {
    if (i != n-1){
      k = min(k, aa[i].value/(abs(maxidx - to!int(aa[i].index))));
      k = min(k, aa[i].value/(abs(minidx - to!int(aa[i].index))));
    }

    maxidx = max(maxidx, to!int(aa[i].index));
    minidx = min(minidx, to!int(aa[i].index));
  }

  writeln(k);
}

import std.stdio, std.algorithm, std.conv, std.array, std.string, std.math, std.typecons, std.numeric, std.bigint;

void main()
{
    auto N = readln.chomp.to!int;
    auto AS = readln.split.to!(int[]);

    auto k = int.max, x = int.max, n = N;
    size_t i, j = N-1;
    while (i <= j) {
        --n;
        x = min(x, AS[i]);
        x = min(x, AS[j]);
        k = min(k, x / n);
        ++i;
        --j;
    }
    writeln(k);
}


import std.algorithm;
import std.container;
import std.conv;
import std.format;
import std.range;
import std.stdio;
import std.string;

void main() {
    int n,k;
    readf!" %s %s"(n,k);

    int[] d = new int[](k);

    foreach (i; 0 .. n) {
        int a;
        readf!" %s"(a);
        d[a%k]++;
    }

    int ans = d[0]/2*2;
    if (k % 2 == 0) {
        ans += d[k/2]/2*2;
    }
    foreach (i; 1 .. k) {
        if (i == k-i) continue;
        ans += min(d[i], d[k-i]);
    }

    writeln(ans);
}

import std.stdio, std.array, std.string, std.conv, std.algorithm;
import std.typecons, std.range, std.random, std.math, std.container;
import std.numeric, std.bigint, core.bitop, core.stdc.string;

void main() {
    auto s = readln.split.map!(to!int);
    auto N = s[0];
    auto K = s[1];
    auto A = readln.split.map!(x => x.to!int % K).array;

    auto cnt = new int[](K+1);
    foreach (a; A) cnt[a] += 1;

    int ans = 0;
    foreach (i; 0..K) {
        if (i * 2 % K == 0) {
            ans += cnt[i] / 2;
            cnt[i] /= 2;
        } else {
            int m = min(cnt[i], cnt[K-i]);
            ans += m;
            cnt[i] -= m;
            cnt[K-i] -= m;
        }
    }

    ans *= 2;
    ans.writeln;
}

import std.algorithm;
import std.container;
import std.conv;
import std.format;
import std.range;
import std.stdio;
import std.string;

void main() {
    int n,k;
    readf!" %s %s"(n,k);

    int[] d = new int[](k);

    foreach (i; 0 .. n) {
        int a;
        readf!" %s"(a);
        d[a%k]++;
    }

    int ans = d[0]/2*2;
    foreach (i; 1 .. k) {
        ans += min(d[i], d[k-i]);
    }

    writeln(ans);
}


import std.conv, std.functional, std.range, std.stdio, std.string;
import std.algorithm, std.array, std.bigint, std.bitmanip, std.complex, std.container, std.math, std.mathspecial, std.numeric, std.regex, std.typecons;
import core.bitop;

class EOFException : Throwable { this() { super("EOF"); } }
string[] tokens;
string readToken() { for (; tokens.empty; ) { if (stdin.eof) { throw new EOFException; } tokens = readln.split; } auto token = tokens.front; tokens.popFront; return token; }
int readInt() { return readToken.to!int; }
long readLong() { return readToken.to!long; }
real readReal() { return readToken.to!real; }

bool chmin(T)(ref T t, in T f) { if (t > f) { t = f; return true; } else { return false; } }
bool chmax(T)(ref T t, in T f) { if (t < f) { t = f; return true; } else { return false; } }

int binarySearch(alias pred, T)(in T[] as) { int lo = -1, hi = cast(int)(as.length); for (; lo + 1 < hi; ) { const mid = (lo + hi) >> 1; (unaryFun!pred(as[mid]) ? hi : lo) = mid; } return hi; }
int lowerBound(T)(in T[] as, T val) { return as.binarySearch!(a => (a >= val)); }
int upperBound(T)(in T[] as, T val) { return as.binarySearch!(a => (a > val)); }

void main() {
  try {
    for (; ; ) {
      const N = readInt();
      const U = readLong();
      auto E = new long[N];
      foreach (i; 0 .. N) {
        E[i] = readLong();
      }

      real ans = -1.0L;
      foreach (i; 0 .. N - 1) {
        const j = i + 1;
        const k = E.upperBound(E[i] + U) - 1;
        if (j < k) {
          chmax(ans, cast(real)(E[k] - E[j]) / (E[k] - E[i]));
        }
      }
      if (ans < 0) {
        writeln(-1);
      } else {
        writefln("%.10f", ans);
      }
    }
  } catch (EOFException e) {
  }
}

import std.algorithm, std.container, std.conv, std.math, std.range, std.typecons, std.stdio, std.string;

auto rdsp(){return readln.splitter;}
void pick(R,T)(ref R r,ref T t){t=r.front.to!T;r.popFront;}
void readV(T...)(ref T t){auto r=rdsp;foreach(ref v;t)pick(r,v);}
void readA(T)(size_t n,ref T[]t){t=new T[](n);auto r=rdsp;foreach(ref v;t)pick(r,v);}

void main()
{
  int n, u; readV(n, u);
  int[] e; readA(n, e);
  auto es = e.assumeSorted;

  auto y = -1.0L;
  foreach (i; 0..n-2) {
    if (e[i+2]-e[i] > u) continue;
    auto ei = e[i], ej = e[i+1];
    auto ek = es.lowerBound(ei+u+1).back;
    y = max(y, (ek-ej).to!real/(ek-ei));
  }

  if (y < 0)
    writeln(-1);
  else
    writefln("%.10f", y);
}

import std.algorithm, std.conv, std.range, std.stdio, std.string;

void readV(T...)(ref T t){auto r=readln.splitter;foreach(ref v;t){v=r.front.to!(typeof(v));r.popFront;}}
void readA(T)(size_t n,ref T t){t=new T(n);auto r=readln.splitter;foreach(ref v;t){v=r.front.to!(ElementType!T);r.popFront;}}
void readM(T...)(size_t n,ref T t){foreach(ref v;t)v=new typeof(v)(n);foreach(i;0..n){auto r=readln.splitter;foreach(ref v;t){v[i]=r.front.to!(ElementType!(typeof(v)));r.popFront;}}}
void readS(T)(size_t n,ref T t){t=new T(n);foreach(ref v;t){auto r=readln.splitter;foreach(ref j;v.tupleof){j=r.front.to!(typeof(j));r.popFront;}}}

void main()
{
  int n, u; readV(n, u);
  int[] e; readA(n, e);
  auto es = e.assumeSorted;

  auto y = -1.0L;
  foreach (i; 0..n-2) {
    if (e[i+2]-e[i] > u) continue;
    auto ei = e[i], ej = e[i+1];
    auto ek = es.lowerBound(ei+u+1).back;
    y = max(y, (ek-ej).to!real/(ek-ei));
  }

  if (y < 0)
    writeln(-1);
  else
    writefln("%.10f", y);
}


import std.stdio;
import std.range;
import std.array;
import std.functional;
import std.algorithm;
import std.conv;
import std.container;
import std.math;
import std.numeric;
import std.string;

void main() {
    int n; readf("%d\n", &n);
    int[] as = readln.chomp.split(" ").map!(to!int).array;
    int[int] x;
    foreach (a; as) {
        x[a]++;
    }
    auto bs = redBlackTree!int([]);
    foreach (a; as) {
        int b = a + 1;
        if (!x.get(b, 0)) bs.insert(b);
    }
    int[] r = as.dup;
    foreach (i, a; as) {
        if (x[a] > 1) {
            int b = bs.upperBound(a).front;
            bs.removeKey(b);
            r[i] = b;
            x[a]--;
            if (!x.get(b + 1, 0)) bs.insert(b + 1);
        }
    }
    write(r[0]);
    foreach (e; r[1 .. $]) {
        write(" ", e);
    }
    write("\n");
}

import std.stdio, std.algorithm;

void main() {
    int n;
    readf(" %d", &n);

    auto a = new int[2][n];
    foreach(i; 0..n) {
        readf(" %d", &a[i][0]);
        a[i][1] = i;
    }
    sort!("a < b", SwapStrategy.stable)(a);

    auto b = new int[n];
    foreach(i; 0..n) {
        b[a[i][1]] = max(a[i][0], i > 0 ? b[a[i-1][1]]+1 : 0);
    }

    writefln("%(%s %)", b);
}

import std.algorithm;
import std.array;
import std.container;
import std.conv;
import std.exception;
import std.functional;
import std.math;
import std.numeric;
import std.range;
import std.stdio;
import std.string;
import std.typecons;
import core.bitop;

void main ()
{
	int n;
	while (readf (" %s", &n) > 0)
	{
		auto a = new int [n];
		foreach (ref x; a)
		{
			readf (" %s", &x);
		}

		alias Tuple !(int, "x", int, "k") pair;
		pair [] c;
		foreach (i, x; a)
		{
			c ~= pair (x, i);
		}
		sort !("a < b", SwapStrategy.stable) (c);

		int [int] p;
		foreach (e; c)
		{
			int x = e.x;
			while (x in p)
			{
				x = p[x];
			}
			a[e.k] = x;
			p[x] = x + 1;
			int y = e.x;
			while (y in p)
			{
				int z = p[y];
				p[y] = x + 1;
				y = z;
			}
		}

		writefln ("%(%s %)", a);
	}
}

import std.stdio;
import std.range;
import std.array;
import std.functional;
import std.algorithm;
import std.conv;
import std.container;
import std.math;
import std.numeric;
import std.string;

void main() {
    int n; readf("%d\n", &n);
    int[] as = readln.chomp.split(" ").map!(to!int).array;
    int[int] x;
    foreach (a; as) {
        x[a]++;
    }
    auto bs = redBlackTree!int([]);
    foreach (a; as) {
        int b = a + 1;
        if (!x.get(b, 0)) bs.insert(b);
    }
    int[] r = as.dup;
    foreach (i, a; as) {
        if (x[a] > 1) {
            int b = bs.upperBound(a).front;
            bs.removeKey(b);
            bs.insert(b + 1);
            r[i] = b;
            x[a]--;
        }
    }
    r.map!(to!string).join(" ").writeln;
}


import std.algorithm, std.array, std.container, std.conv, std.math, std.range, std.stdio, std.string;

void main() {
    foreach(t; 0 .. to!int(readln.chomp)) {
        int n = to!int(readln.chomp);
        auto nums = readln.split.map!(to!int).array.sort;
        int mn = int.max, ans = 1;
        foreach(i; 1 .. n) {
            mn = min(mn, nums[i] - nums[i-1]);
            if(mn < nums[i]) break;
            ans++;
        }
        writeln(ans);
    }
}

import std.stdio;
import std.conv;
import std.algorithm;
import std.array;
import std.string;
import std.uni;
import std.math;
import std.container.rbtree;
import std.range;
import std.numeric;

void main()
{
    auto t = to!long(readln().chomp);
    OUTER: foreach(_; 0..t)
    {
        auto n = readln().chomp.to!int;
        auto arr = readln().chomp.splitter(" ").map!(to!int).array.sort;

        int diff = int.max;
        int res= 1;

        for(int i = 1; i < arr.length;i++)
        {
            diff = min(diff, arr[i] - arr[i-1]);
            if(diff < arr[i]) break;
            res++;
        }

        writeln(res);
    }
}

import std.stdio;
import std.conv;
import std.algorithm;
import std.array;
import std.string;
import std.uni;
import std.math;
import std.container.rbtree;
import std.range;
import std.numeric;

void main()
{
    auto t = to!long(readln().chomp);
    OUTER: foreach(_; 0..t)
    {
        auto n = readln().chomp.to!int;
        auto arr = readln().chomp.splitter(" ").map!(to!int).array.sort.array;

        int diff = int.max;
        int res= 1;

        for(int i = 1; i < arr.length;i++)
        {
            diff = min(diff, arr[i] - arr[i-1]);
            if(diff < arr[i]) break;
            res++;
        }

        writeln(res);
    }
}

// Vicfred
// https://codeforces.com/contest/1529/problem/B
// greedy
import std.algorithm;
import std.array;
import std.conv;
import std.math;
import std.stdio;
import std.string;

void main() {
    int t = readln.chomp.to!int;

while(t--) {
    int n = readln.chomp.to!int;
    int[] a = readln.split.map!(to!int).array;
    int minima = int.max;
    int ans = 1;
    a.sort;
    for(int i = 1; i < n; ++i) {
        minima = min(minima, a[i] - a[i - 1]);
        if(a[i] <= 0) {
            ans += 1;
            continue;
        } else {
            if(a[i] <= minima) {
                ans += 1;
            }
            break;
        }
    }
    ans.writeln;
}
}

import std.stdio, std.conv, std.functional, std.string;
import std.algorithm, std.array, std.container, std.range, std.typecons;
import std.bigint, std.numeric, std.math, std.random;
import core.bitop;

string FMT_F = "%.10f";

static File _f;
void file_io(string fn) { _f = File(fn, "r"); }
static string[] s_rd;
T _RD(T = long)() { while(!s_rd.length) s_rd = readln.chomp.split; string res = s_rd[0]; s_rd.popFront; return res.to!T; }
T _RD(T = long)(File f) { while(!s_rd.length) s_rd = f.readln.chomp.split; string res = s_rd[0]; s_rd.popFront; return res.to!T; }
T[] _RDA(T = long)(T fix = 0) { auto r = readln.chomp.split.to!(T[]); r[] += fix; return r; }
T[] _RDA(T = long)(File f, T fix = 0) { auto r = f.readln.chomp.split.to!(T[]); r[] += fix; return r; }
T RD(T = long)() { if (_f.isOpen) return _RD!T(_f); else return _RD!T; }
T[] RDA(T = long)(T fix = 0) { if (_f.isOpen)  return _RDA!T(_f, fix); else return _RDA!T(fix); }

size_t[] MAKE_IDX(alias less = "a < b", Range)(Range range) { auto idx = new size_t[](range.length); makeIndex!(less)(range, idx); return idx;}
size_t MIN_POS(alias less = "a < b", Range)(Range range) { auto r = minPos!(less)(range); return range.length - r.length; }

void chmin(T)(ref T x, T y) { x = min(x, y); } void chmax(T)(ref T x, T y) { x = max(x, y); }
bool inside(T)(T x, T b, T e) { return x >= b && x < e; }
T lcm(T)(T x, T y) { return x * (y / gcd(x, y)); }
double[] rotate(double[] vec, double rad) { return [cos(rad)*vec[0] - sin(rad)*vec[1], sin(rad)*vec[0] + cos(rad)*vec[1]]; }

//long mod = 10^^9 + 7;
long mod = 998_244_353;
//long mod = 1_000_003;
void moda(ref long x, long y) { x = (x + y) % mod; }
void mods(ref long x, long y) { x = ((x + mod) - (y % mod)) % mod; }
void modm(ref long x, long y) { x = (x * y) % mod; }
void modpow(ref long x, long y) { if (!y) { x = 1; return; } auto t = x; x.modpow(y>>1); x.modm(x); if (y&1) x.modm(t); }
void modd(ref long x, long y) { y.modpow(mod - 2); x.modm(y); }

void main()
{
	auto t = RD!int;
	auto ans = new long[](t);
	foreach (ti; 0..t)
	{
		auto n = RD!int;
		auto a = RDA;

		long[] b, c;
		foreach (i; 0..n)
		{
			if (a[i] > 0)
				b ~= a[i];
			else
				c ~= a[i];
		}

		long rmv, x;
		if (!b.empty)
		{
			rmv = b.length - 1;
			x = b.minElement;
		}
		c.sort;
		long y = long.max;
		foreach (i; 0..cast(int)c.length-1)
		{
			y.chmin(c[i+1] - c[i]);
		}
		if (y < x)
			++rmv;
		ans[ti] = n - rmv;
	}

	foreach (e; ans)
		writeln(e);
	stdout.flush;
	debug readln;
}

import std.algorithm, std.array, std.container, std.conv, std.math, std.range, std.stdio, std.string;

void main() {
    foreach(t; 0 .. to!int(readln.chomp)) {
        int n = to!int(readln.chomp);
        auto nums = readln.split.map!(to!int).array;
        auto cnt = new int[3];
        foreach(e; nums) {
            if(e < 0) {
                cnt[0]++;
            } else if(!e) {
                cnt[1]++;
            } else {
                cnt[2] = true;
            }
        }
        writeln(cnt[0] + (cnt[1] > 1 ? cnt[1] : cnt[1]+cnt[2]));
    }
}


// c
import std.conv, std.functional, std.range, std.stdio, std.string;
import std.algorithm, std.array, std.bigint, std.bitmanip, std.complex, std.container, std.math, std.mathspecial, std.numeric, std.regex, std.typecons;
import core.bitop;

class EOFException : Throwable { this() { super("EOF"); } }
string[] tokens;
string readToken() { for (; tokens.empty; ) { if (stdin.eof) { throw new EOFException; } tokens = readln.split; } auto token = tokens.front; tokens.popFront; return token; }
int readInt() { return readToken.to!int; }
long readLong() { return readToken.to!long; }
real readReal() { return readToken.to!real; }

bool chmin(T)(ref T t, in T f) { if (t > f) { t = f; return true; } else { return false; } }
bool chmax(T)(ref T t, in T f) { if (t < f) { t = f; return true; } else { return false; } }

int binarySearch(alias pred, T)(in T[] as) { int lo = -1, hi = cast(int)(as.length); for (; lo + 1 < hi; ) { const mid = (lo + hi) >> 1; (unaryFun!pred(as[mid]) ? hi : lo) = mid; } return hi; }
int lowerBound(T)(in T[] as, T val) { return as.binarySearch!(a => (a >= val)); }
int upperBound(T)(in T[] as, T val) { return as.binarySearch!(a => (a > val)); }

alias KV = Tuple!(int, "key", int, "val");
KV[] history;

int root(int[] uf, int u) {
  // return (uf[u] < 0) ? u : (uf[u] = uf.root(uf[u]));
  if (uf[u] < 0) {
    return u;
  } else {
    const r = uf.root(uf[u]);
    history ~= KV(u, uf[u]);
    return uf[u] = r;
  }
}
bool connect(int[] uf, int u, int v) {
  u = uf.root(u);
  v = uf.root(v);
  if (u == v) return false;
  if (uf[u] > uf[v]) swap(u, v);
  history ~= KV(u, uf[u]);
  uf[u] += uf[v];
  history ~= KV(v, uf[v]);
  uf[v] = u;
  return true;
}

void main() {
  try {
    for (; ; ) {
      const N = readInt();
      const M = readInt();
      const K = readInt();
      auto C = new int[N];
      foreach (u; 0 .. N) {
        C[u] = readInt() - 1;
      }
      auto A = new int[M];
      auto B = new int[M];
      foreach (i; 0 .. M) {
        A[i] = readInt() - 1;
        B[i] = readInt() - 1;
      }

      auto uss = new int[][K];
      foreach (u; 0 .. N) {
        uss[C[u]] ~= u;
      }

      auto uf = new int[N * 2];
      uf[] = -1;

      alias Entry = Tuple!(int, "ca", int, "cb", int, "i");
      Entry[] es;
      foreach (i; 0 .. M) {
        if (C[A[i]] > C[B[i]]) {
          swap(A[i], B[i]);
        }
        if (C[A[i]] == C[B[i]]) {
          uf.connect(A[i] * 2 + 0, B[i] * 2 + 1);
          uf.connect(A[i] * 2 + 1, B[i] * 2 + 0);
        } else {
          es ~= Entry(C[A[i]], C[B[i]], i);
        }
      }
      es.sort;
      const esLen = cast(int)(es.length);

      auto good = new bool[K];
      good[] = true;
      foreach (k; 0 .. K) {
        foreach (u; uss[k]) {
          good[k] = good[k] && (uf.root(u * 2 + 0) != uf.root(u * 2 + 1));
        }
      }
      debug {
        writeln("good = ", good);
      }
      const numGood = cast(long)(good.count(true));
      long ans = numGood * (numGood - 1) / 2;

      for (int g = 0, h; g < esLen; g = h) {
        for (h = g; h < esLen && (es[g].ca == es[h].ca && es[g].cb == es[h].cb); ++h) {}
        if (good[es[g].ca] && good[es[g].cb]) {
          debug {
            writeln(es[g .. h]);
          }
          history = [];
          foreach (ref e; es[g .. h]) {
            const i = e.i;
            uf.connect(A[i] * 2 + 0, B[i] * 2 + 1);
            uf.connect(A[i] * 2 + 1, B[i] * 2 + 0);
          }
          bool ok = true;
          foreach (ref e; es[g .. h]) {
            const i = e.i;
            ok = ok && (uf.root(A[i] * 2 + 0) != uf.root(A[i] * 2 + 1));
            ok = ok && (uf.root(B[i] * 2 + 0) != uf.root(B[i] * 2 + 1));
          }
          if (!ok) {
            --ans;
          }
          foreach_reverse (ref kv; history) {
            uf[kv.key] = kv.val;
          }
        }
      }

      writeln(ans);
    }
  } catch (EOFException e) {
  }
}

import std.algorithm;
import std.conv;
import std.range;
import std.stdio;
import std.string;
import std.typecons;

void main ()
{
	int n, m, k;
	while (readf !(" %s %s %s") (n, m, k) > 0)
	{
		readln;
		auto g = readln.splitter.map !(to !(int)).array;
		g[] -= 1;
		alias Edge = Tuple !(int, q{u}, int, q{v});
		Edge [] [Edge] edgesByPair;
		foreach (j; 0..m)
		{
			Edge e;
			readf !(" %s %s") (e.u, e.v);
			e.u -= 1;
			e.v -= 1;

			auto pair = Edge (g[e.u], g[e.v]);
			if (pair.u > pair.v)
			{
				swap (pair.u, pair.v);
			}
			edgesByPair[pair] ~= e;
		}

		alias Parent = Tuple !(int, q{v}, int, q{xor});
		auto p = new Parent [n];
		auto rank = new int [n];
		foreach (u; 0..n)
		{
			p[u] = Parent (u, 0);
			rank[u] = 1;
		}

		auto root (int v)
		{
			auto res = Parent (v, 0);
			while (res.v != p[res.v].v)
			{
				res.xor ^= p[res.v].xor;
				res.v = p[res.v].v;
			}
			return res;
		}

		alias Record = Tuple !(int, q{u}, int, q{v}, int, q{xor},
		    int, q{w}, int, q{rank});
		Record [] history;

		auto unite (const ref Edge e, bool doRecord = false)
		{
			auto pu = root (e.u);
			auto pv = root (e.v);
			auto u = pu.v;
			auto v = pv.v;
			auto xor = pu.xor ^ pv.xor;
			debug {writefln !("unite: %s %s %s") (u, v, xor);}
			if (u == v)
			{
				return (xor == 1);
			}
			xor ^= 1;
			if (rank[u] > rank[v])
			{
				swap (u, v);
			}
			if (doRecord)
			{
				history ~= Record (u, p[u].v, p[u].xor,
				    v, rank[v]);
			}
			if (rank[u] == rank[v])
			{
				rank[v] += 1;
			}
			p[u] = Parent (v, xor);
			debug {writefln !("p[%s] = %s %s") (u, v, xor);}
			return true;
		}

		auto badGroup = new bool [k];

		foreach (i; 0..k)
		{
			auto pair = Edge (i, i);
			if (pair in edgesByPair)
			{
				foreach (e; edgesByPair[pair])
				{
					if (!unite (e))
					{
						badGroup[i] = true;
					}
				}
			}
		}

		auto totalBad = sum (badGroup, 0);
		debug {writeln ("totalBad = ", totalBad);}
		long res = k - totalBad;
		res = (res * (res - 1L)) / 2;

		foreach (pair, edges; edgesByPair)
		{
			if (pair.u == pair.v)
			{
				continue;
			}
			if (badGroup[pair.u] || badGroup[pair.v])
			{
				continue;
			}

			bool badPair = false;
			foreach (e; edges)
			{
				if (!unite (e, true))
				{
					badPair = true;
				}
			}
			if (badPair)
			{
				res -= 1;
			}
			foreach_reverse (r; history)
			{
				rank[r.w] = r.rank;
				p[r.u] = Parent (r.v, r.xor);
				debug {writefln !("p[%s] reverted to %s %s")
				    (r.u, r.v, r.xor);}
			}
			history = null;
		}

		writeln (res);
	}
}

import std.algorithm;
import std.conv;
import std.range;
import std.stdio;
import std.string;
import std.typecons;

void main ()
{
	int n, m, k;
	while (readf !(" %s %s %s") (n, m, k) > 0)
	{
		readln;
		auto g = readln.splitter.map !(to !(int)).array;
		g[] -= 1;
		alias Edge = Tuple !(int, q{u}, int, q{v});
		Edge [] [Edge] edgesByPair;
		foreach (j; 0..m)
		{
			Edge e;
			readf !(" %s %s") (e.u, e.v);
			e.u -= 1;
			e.v -= 1;

			auto pair = Edge (g[e.u], g[e.v]);
			if (pair.u > pair.v)
			{
				swap (pair.u, pair.v);
			}
			edgesByPair[pair] ~= e;
		}

		alias Parent = Tuple !(int, q{v}, int, q{xor});
		auto p = new Parent [n];
		auto rank = new int [n];
		foreach (u; 0..n)
		{
			p[u] = Parent (u, 0);
			rank[u] = 1;
		}

		auto root (int v)
		{
			auto res = Parent (v, 0);
			while (res.v != p[res.v].v)
			{
				res.xor ^= p[res.v].xor;
				res.v = p[res.v].v;
			}
			return res;
		}

		alias Record = Tuple !(int, q{u}, int, q{v}, int, q{xor},
		    int, q{w}, int, q{rank});
		Record [] history;

		auto unite (const ref Edge e, bool doRecord = false)
		{
			auto pu = root (e.u);
			auto pv = root (e.v);
			auto u = pu.v;
			auto v = pv.v;
			auto xor = pu.xor ^ pv.xor;
			debug {writefln !("unite: %s %s %s") (u, v, xor);}
			if (u == v)
			{
				return (xor == 1);
			}
			xor ^= 1;
			if (rank[u] > rank[v])
			{
				swap (u, v);
			}
			if (doRecord)
			{
				history ~= Record (u, p[u].v, p[u].xor,
				    v, rank[v]);
			}
			if (rank[u] == rank[v])
			{
				rank[v] += 1;
			}
			p[u] = Parent (v, xor);
			debug {writefln !("p[%s] = %s %s") (u, v, xor);}
			return true;
		}

		auto badGroup = new bool [k];

		foreach (i; 0..k)
		{
			auto pair = Edge (i, i);
			if (pair in edgesByPair)
			{
				foreach (e; edgesByPair[pair])
				{
					if (!unite (e))
					{
						badGroup[i] = true;
					}
				}
			}
		}

		auto totalBad = sum (badGroup, 0);
		debug {writeln ("totalBad = ", totalBad);}
		long res = k - totalBad;
		res = (res * (res - 1L)) / 2;

		foreach (pair, edges; edgesByPair)
		{
			if (pair.u == pair.v)
			{
				continue;
			}

			bool badPair = false;
			foreach (e; edges)
			{
				if (!unite (e, true))
				{
					badPair = true;
				}
			}
			if (badPair)
			{
				res -= 1;
			}
			foreach_reverse (r; history)
			{
				rank[r.w] = r.rank;
				p[r.u] = Parent (r.v, r.xor);
				debug {writefln !("p[%s] reverted to %s %s")
				    (r.u, r.v, r.xor);}
			}
			history = null;
		}

		writeln (res);
	}
}


import std.stdio, std.conv, std.functional, std.string;
import std.algorithm, std.array, std.container, std.range, std.typecons;
import std.bigint, std.numeric, std.math, std.random;
import core.bitop;

string FMT_F = "%.10f";

static File _f;
void file_io(string fn) { _f = File(fn, "r"); }
static string[] s_rd;
T _RD(T = long)() { while(!s_rd.length) s_rd = readln.chomp.split; string res = s_rd[0]; s_rd.popFront; return res.to!T; }
T _RD(T = long)(File f) { while(!s_rd.length) s_rd = f.readln.chomp.split; string res = s_rd[0]; s_rd.popFront; return res.to!T; }
T[] _RDA(T = long)(T fix = 0) { auto r = readln.chomp.split.to!(T[]); r[] += fix; return r; }
T[] _RDA(T = long)(File f, T fix = 0) { auto r = f.readln.chomp.split.to!(T[]); r[] += fix; return r; }
T RD(T = long)() { if (_f.isOpen) return _RD!T(_f); else return _RD!T; }
T[] RDA(T = long)(T fix = 0) { if (_f.isOpen)  return _RDA!T(_f, fix); else return _RDA!T(fix); }

size_t[] MAKE_IDX(alias less = "a < b", Range)(Range range) { auto idx = new size_t[](range.length); makeIndex!(less)(range, idx); return idx;}
size_t MIN_POS(alias less = "a < b", Range)(Range range) { auto r = minPos!(less)(range); return range.length - r.length; }

void chmin(T)(ref T x, T y) { x = min(x, y); } void chmax(T)(ref T x, T y) { x = max(x, y); }
bool inside(T)(T x, T b, T e) { return x >= b && x < e; }
T lcm(T)(T x, T y) { return x * (y / gcd(x, y)); }

long mod = 10^^9 + 7;
//long mod = 998_244_353;
//long mod = 1_000_003;
void moda(T)(ref T x, T y) { x = (x + y) % mod; }
void mods(T)(ref T x, T y) { x = ((x + mod) - (y % mod)) % mod; }
void modm(T)(ref T x, T y) { x = (x * y) % mod; }
void modpow(T)(ref T x, T y) { if (!y) { x = 1; return; } auto t = x; x.modpow(y>>1); x.modm(x); if (y&1) x.modm(t); }
void modd(T)(ref T x, T y) { y.modpow(mod - 2); x.modm(y); }

void main()
{
	auto t = RD!int;
	auto ans = new bool[](t);
	foreach (ti; 0..t)
	{
		auto n = RD!int;
		auto a = RDA!int;

		ans[ti] = a.front < a.back;
	}

	foreach (e; ans)
	{
		writeln(e ? "YES" : "NO");
	}
	stdout.flush;
	debug readln;
}

import std.algorithm;
import std.conv;
import std.math;
import std.range;
import std.stdio;
import std.string;

void main ()
{
	auto tests = readln.strip.to !(int);
	foreach (test; 0..tests)
	{
		auto n = readln.strip.to !(int);
		auto a = readln.splitter.map !(to !(long)).array;
		writeln (a.front < a.back ? "YES" : "NO");
	}
}

import std.conv, std.functional, std.range, std.stdio, std.string;
import std.algorithm, std.array, std.bigint, std.bitmanip, std.complex, std.container, std.math, std.mathspecial, std.numeric, std.regex, std.typecons;
import core.bitop;

class EOFException : Throwable { this() { super("EOF"); } }
string[] tokens;
string readToken() { for (; tokens.empty; ) { if (stdin.eof) { throw new EOFException; } tokens = readln.split; } auto token = tokens.front; tokens.popFront; return token; }
int readInt() { return readToken.to!int; }
long readLong() { return readToken.to!long; }
real readReal() { return readToken.to!real; }

bool chmin(T)(ref T t, in T f) { if (t > f) { t = f; return true; } else { return false; } }
bool chmax(T)(ref T t, in T f) { if (t < f) { t = f; return true; } else { return false; } }

int binarySearch(alias pred, T)(in T[] as) { int lo = -1, hi = cast(int)(as.length); for (; lo + 1 < hi; ) { const mid = (lo + hi) >> 1; (unaryFun!pred(as[mid]) ? hi : lo) = mid; } return hi; }
int lowerBound(T)(in T[] as, T val) { return as.binarySearch!(a => (a >= val)); }
int upperBound(T)(in T[] as, T val) { return as.binarySearch!(a => (a > val)); }

void main() {
  try {
    for (; ; ) {
      const numCases = readInt();
      foreach (caseId; 0 .. numCases) {
        const N = readInt();
        auto A = new int[N];
        foreach (i; 0 .. N) {
          A[i] = readInt();
        }

        writeln((A[0] < A[N - 1]) ? "YES" : "NO");
      }
    }
  } catch (EOFException e) {
  }
}


import core.bitop;
import core.checkedint;
//import core.stdc.stdio;
import core.stdc.stdlib: alloca, malloc, calloc, realloc, _Exit;
import core.stdc.string;
import std.algorithm;
import std.array;
import std.ascii;
import std.bigint;
import std.bitmanip;
import std.container;
import std.conv;
import std.exception;
import std.functional;
import std.math;
import std.meta;
import std.numeric;
import std.random;
import std.range;
import std.regex;
import std.stdio;
import std.string;
import std.typecons;

__gshared:

alias BitSet(size_t n) = size_t[(n + size_t.sizeof * 8 - 1) / (size_t.sizeof * 8)];

auto getAddrTuple() {
    return tuple();
}

auto getAddrTuple(T, U...)(ref T head, ref U tail) {
    return tuple(&head, getAddrTuple(tail).expand);
}

bool read(T...)(ref T vars) if (vars.length > 0) {
    enum spec = ' ' ~ replicate("%s ", vars.length);
    return readf(spec, getAddrTuple(vars).expand) == vars.length;
}

void memSet(T, size_t n)(ref T[n] a, ubyte value) {
    memset(a.ptr, value, a.sizeof);
}

void memSet(T)(T[ ] a, ubyte value) {
    memset(a.ptr, value, a.length * T.sizeof);
}

auto pairwise(R)(R range) if (isForwardRange!R) {
    return lockstep(range, dropOne(range));
}

struct Task {
    bool coproc;
    int deps;
    Task*[ ] next;

    void perform(ref Array!(Task*) q, bool traverseCoproc) {
        assert(!deps);
        assert(coproc == traverseCoproc);
        foreach (t; next) {
            assert(t.deps >= 1);
            if (!--t.deps) {
                if (t.coproc == traverseCoproc)
                    t.perform(q, traverseCoproc);
                else
                    q ~= t;
            }
        }
    }
}

Task[100_001] _tasks;

void main() {
    int n, m;
    Array!(Task*)[2] q;
    while (read(n, m)) {
        auto tasks = _tasks[0 .. n + 1];
        version (LocalProject)
            tasks[ ] = Task.init;
        q[0].clear();
        char c;
        foreach (ref t; tasks[0 .. n]) {
            read(c);
            t.coproc = c == '1';
        }
        while (m--) {
            int a, b;
            read(a, b);
            tasks[a].deps++;
            tasks[b].next ~= &tasks[a];
        }
        foreach (ref t; tasks[0 .. n])
            if (!t.deps) {
                t.deps = 1;
                tasks[n].next ~= &t;
            }

        q[0] ~= &tasks[n];
        int result = 0;
        do {
            q[1].clear();
            foreach (t; q[0])
                t.perform(q[1], false);
            q[0].clear();
            result += !q[1].empty;
            foreach (t; q[1])
                t.perform(q[0], true);
        } while (!q[0].empty);
        writeln(result);
    }

    stdout.flush();
    _Exit(0);
}

import std.stdio, std.string, std.conv, std.algorithm, std.numeric;
import std.range, std.array, std.math, std.typecons, std.container, core.bitop;

void main() {
    int n,m;
    scan(n,m);
    auto e = readln.split.to!(int[]);
    auto adj = new int[][](n, 0);
    foreach (i ; 0 .. m) {
        int t1,t2;
        scan(t1,t2);
        adj[t1] ~= t2;
    }

    auto memo = new int[](n);
    memo[] = -1;

    int dfs(int i) {
        if (memo[i] > -1) return memo[i];
        if (adj[i].empty) {
            memo[i] = e[i] == 1;
            return memo[i];
        }
        memo[i] = 0;
        if (e[i] == 1) {
            foreach (j ; adj[i]) {
                memo[i] = max(memo[i], dfs(j) + (e[j] == 0));
            }
        }
        else {
            foreach (j ; adj[i]) {
                memo[i] = max(memo[i], dfs(j));
            }
        }

        return memo[i];
    }

    int ans;

    foreach (i ; 0 .. n) {
        ans = max(ans, dfs(i));
    }

    debug {
        writeln(memo);
    }

    writeln(ans);
}

void scan(T...)(ref T args) {
    string[] line = readln.split;
    foreach (ref arg; args) {
        arg = line.front.to!(typeof(arg));
        line.popFront();
    }
    assert(line.empty);
}

void fillAll(R, T)(ref R arr, T value) {
    static if (is(typeof(arr[] = value))) {
        arr[] = value;
    }
    else {
        foreach (ref e; arr) {
            fillAll(e, value);
        }
    }
}

import std.stdio;
import std.uni;
import std.conv;
import std.container;
import std.functional;
import std.algorithm;
import std.array;
import std.typecons;
import std.range;
import std.numeric;

void main(string[] args)
{
  inputFile = stdin;
  auto n = next!int;
  auto m = next!int;
  auto noDependencies = new int[](n);
  auto dependencies = new int[][](n);
  auto dependants = new int[][](n);
  auto type = next!int(n);
  enum main = 0;
  enum copr = 1;
  foreach(dep; 0 .. m)
    {
      auto t1 = next!int;
      auto t2 = next!int;
      noDependencies[t1]++;
      dependencies[t1] ~= t2;
      dependants[t2] ~= t1;
    }
  DList!int[2] todo;
  todo[0] = DList!int();
  todo[1] = DList!int();
  foreach(i; 0 .. n)
    {
      if (noDependencies[i] == 0)
	{
	  todo[type[i]].insertBack(i);
	}
    }
  int coprSets = 0;
  while(true)
    {
      if (todo[0].empty && todo[1].empty)
	{
	  return coprSets.writeln;
	}
      foreach(typeToDo; 0 .. 2)
	{
	  if (typeToDo == copr && !todo[typeToDo].empty)
	    {
	      coprSets++;
	    }
	  while(!todo[typeToDo].empty)
	    {
	      auto ntask = todo[typeToDo].front;
	      todo[typeToDo].removeFront;
	      foreach(dependant; dependants[ntask])
		{
		  noDependencies[dependant]--;
		  if (noDependencies[dependant] == 0)
		    {
		      todo[type[dependant]].insertBack(dependant);
		    }
		}
	    }
	}
    }
}
ulong bitCnt(long x)
{
  ulong cnt = 0;
  while(x) {cnt += x & 1; x>>=1;}
  return cnt;
}
alias Arr(T) = Mat!(T, 1);
struct Mat(T, size_t dimension)
{
  T[] _baseArray;
  T[] _slice;
  size_t[dimension] _sizes; size_t dim(size_t i) {return _sizes[i];}
  size_t[dimension] _indexer;
  this(T[] baseArray, size_t[dimension] sizes)
  {
    _baseArray = baseArray;
    _sizes = sizes;
    _indexer[dimension - 1] = 1;
    static foreach_reverse(i; 0 .. dimension - 1)
      _indexer[i] = _indexer[i + 1] * _sizes[i + 1];
    auto requiredSize = _indexer[0] * _sizes[0];
    debug assert(_baseArray.length >= requiredSize);
    _slice = _baseArray[0 .. requiredSize];
  }
  this(size_t[dimension] sizes)
  {
    size_t reqSize = 1;
    static foreach(i; 0 .. dimension)
      reqSize *= sizes[i];
    this(new T[](reqSize), sizes);
  }
  ref auto opIndex()
  {
    pragma(inline, true);
    return _slice[];
  }
  ref auto opIndex(I...)(I i)
  {
    pragma(inline, true);
    debug assert(i.length <= dimension);
    size_t index = mixin(iota(0, i.length).map!(j => text("i[", j, "]*_indexer[", j, "]")).join("+"));
    static if (i.length == dimension)
      {
	return _slice[index];
      }
    else
      {
	enum sliceDimension = dimension - i.length;
	size_t[sliceDimension] remSizes = _sizes[i.length .. $];
	auto basePortion = _slice[index .. index + _indexer[i.length - 1]];
 	return Mat!(T, sliceDimension)(basePortion, remSizes);
      }
  }
  static if (dimension == 2)
    {
      auto identity()
      {
	debug assert(dim(0) == dim(1));
	auto n = dim(0);
	auto id = Mat!(T, 2)([n, n]);
	foreach(k; 0 .. n)
	  id[k, k] = T(1);
	return id;
      }
      bool canMultiply(Mat!(T, 2) b)
      {
	return this.dim(1) == b.dim(0);
      }
      auto opBinary(string op)(Mat!(T, 2) b)
	if (op == "*")
	  {
	    debug assert(canMultiply(b));
	    auto res = Mat!(T, 2)([this.dim(0), b.dim(1)]);
	    foreach(i; 0 .. res.dim(0))
	      foreach(k; 0 .. this.dim(1))
		foreach(j; 0 .. res.dim(1))
		  res[i, j] = res[i, j] + this[i, k] * b[k, j];
	    return res;
	  }
      auto opBinary(string op)(ulong exp)
	if (op == "^^")
	  {
	    return this.pow(identity, exp);
	  }
      mixin interiorBinPow;
    }
}

struct Mod(T, ulong mod)
{
  alias This = Mod!(T, mod);
  T _rep; T rep() {return _rep;}
  this(W)(W w)
  {
    _rep = ((cast(T) w)%mod + mod) % mod;
  }
  static auto plainConstruct(T t)
  {
    pragma(inline, true);
    debug assert(t >= 0 && t < mod);
    auto res = Mod!(T, mod).init;
    res._rep = t;
    return res;
  }
  string toString()
  {
    return to!string(rep);
  }
  debug invariant
  {
    assert(_rep >= 0 && _rep < mod);
  }
  auto opBinary(string op)(This b)
  {
    static if (op == "+")
      {
	T resrep = _rep + b._rep;
	if (resrep >= mod) resrep -= mod;
	return This.plainConstruct(resrep);
      }
    else static if (op == "-")
      {
	T resrep = _rep - b._rep;
	if (resrep < 0) resrep += mod;
	return This.plainConstruct(resrep);
      }
    else static if (op == "*")
      {
	return This(_rep * b._rep);
      }
  }
}

mixin template interiorBinPow()
{
  alias ThisType = typeof(this);
  auto pow(ThisType res, ulong exp)
    {
      if (exp < 0) debug assert(0);
      auto pow = this;
      while(exp)
	{
	  if (exp & 1)
	    res = res * pow;
	  pow = pow * pow;
	  exp >>= 1;
	}
      return res;
    }
}

// INPUT
File inputFile;
DList!string _words;
void _wordsFill()
{
  while (_words.empty) _words.insertBack(inputFile.readln.split);
}
string popWord()
{
  _wordsFill;
  auto word = _words.front;
  _words.removeFront;
  return word;
}
string peekWord()
{
  _wordsFill;
  return _words.front;
}
T next(T)()
{
  return to!T(popWord);
}
T peek(T)()
{
  return to!T(peekWord);
}
auto next(T, S...)(S s)
{
  static if (S.length == 0)
    {
      return to!T(popWord);
    }
  else
    {
      auto res = new typeof(next!T(s[1 .. $]))[](cast(size_t)s[0]);
      foreach(ref elem; res)
        elem = next!T(s[1 .. $]);
      return res;
    }
}

import core.bitop;
import core.checkedint;
//import core.stdc.stdio;
import core.stdc.stdlib: alloca, malloc, calloc, realloc, _Exit;
import core.stdc.string;
import std.algorithm;
import std.array;
import std.ascii;
import std.bigint;
import std.bitmanip;
import std.container;
import std.conv;
import std.exception;
import std.functional;
import std.math;
import std.meta;
import std.numeric;
import std.random;
import std.range;
import std.regex;
import std.stdio;
import std.string;
import std.typecons;

__gshared:

alias BitSet(size_t n) = size_t[(n + size_t.sizeof * 8 - 1) / (size_t.sizeof * 8)];

auto getAddrTuple() {
    return tuple();
}

auto getAddrTuple(T, U...)(ref T head, ref U tail) {
    return tuple(&head, getAddrTuple(tail).expand);
}

bool read(T...)(ref T vars) if (vars.length > 0) {
    enum spec = ' ' ~ replicate("%s ", vars.length);
    return readf(spec, getAddrTuple(vars).expand) == vars.length;
}

void memSet(T, size_t n)(ref T[n] a, ubyte value) {
    memset(a.ptr, value, a.sizeof);
}

void memSet(T)(T[ ] a, ubyte value) {
    memset(a.ptr, value, a.length * T.sizeof);
}

auto pairwise(R)(R range) if (isForwardRange!R) {
    return lockstep(range, dropOne(range));
}

enum TraverseMode: ubyte {
    proc,
    coproc,
}

struct Task {
    bool coproc;
    int deps;
    Task*[ ] next;

    bool perform(ref Array!(Task*) q, TraverseMode mode) {
        assert(coproc == (mode == TraverseMode.coproc));
        bool result = false;
        foreach (t; next) {
            assert(t.deps >= 1);
            if (!--t.deps) {
                if (t.coproc == (mode == TraverseMode.coproc))
                    result |= t.perform(q, mode);
                else if (mode == TraverseMode.proc)
                    result |= t.perform(q, TraverseMode.coproc);
                else {
                    q ~= t;
                    result = true;
                }
            }
        }
        return result;
    }
}

int n;
Task[100_001] _tasks;

void main() {
    int m;
    Array!(Task*)[2] q;
    while (read(n, m)) {
        auto tasks = _tasks[0 .. n + 1];
        version (LocalProject)
            tasks[ ] = Task.init;
        q[0].clear();
        char c;
        foreach (ref t; tasks[0 .. n]) {
            read(c);
            t.coproc = c == '1';
        }
        while (m--) {
            int a, b;
            read(a, b);
            tasks[a].deps++;
            tasks[b].next ~= &tasks[a];
        }
        foreach (ref t; tasks[0 .. n])
            if (!t.deps) {
                t.deps = 1;
                tasks[n].next ~= &t;
            }

        q[0] ~= &tasks[n];
        int result = 0;
        for (bool cur = 0; !q[cur].empty; cur = !cur) {
            q[!cur].clear();
            bool called = false;
            foreach (t; q[cur])
                called |= t.perform(q[!cur], TraverseMode.proc);
            result += called;
        }
        writeln(result);
    }

    stdout.flush();
    _Exit(0);
}


import std.algorithm;
import std.array;
import std.container;
import std.conv;
import std.exception;
import std.functional;
import std.math;
import std.numeric;
import std.range;
import std.stdio;
import std.string;
import std.typecons;
import core.bitop;

immutable int NA = -1;

void main ()
{
	int n, m, k, w;
	while (readf (" %s %s %s %s ", &n, &m, &k, &w) > 0)
	{
		auto a = new string [] [k];
		foreach (u; 0..k)
		{
			foreach (i; 0..n)
			{
				a[u] ~= readln ().strip ();
			}
		}

		auto d = new int [] [] (k, k);
		foreach (u; 0..k)
		{
			d[u][u] = 0;
			foreach (v; 0..u)
			{
				int cur = 0;
				foreach (i; 0..n)
				{
					foreach (j; 0..m)
					{
						cur += (a[u][i][j] !=
						    a[v][i][j]);
					}
				}
				d[u][v] = cur * w;
				d[v][u] = cur * w;
			}
		}

		long res = n * m;
		auto b = new bool [k];
		alias pair = Tuple !(int, "x", int, "y");
		auto e = new pair [k];
		pair [] ans;
		int r = 0;
		b[r] = true;
		foreach (t; 0..k)
		{
			e[t] = pair (int.max, NA);
		}
		e[r] = pair (0, NA);
		ans ~= pair (r, NA);
		foreach (t; 1..k)
		{
			auto z = pair (int.max, NA);
			foreach (v; 0..k)
			{
				if (!b[v])
				{
					if (e[v].x > d[r][v])
					{
						e[v] = pair (d[r][v], r);
					}
					if (z.x > e[v].x)
					{
						z = pair (e[v].x, v);
					}
				}
			}
			assert (z.x < int.max);
			r = z.y;
			if (z.x >= n * m)
			{
				e[r] = pair (n * m, NA);
			}
			b[r] = true;
			res += e[r].x;
			ans ~= pair (r, e[r].y);
		}

		writeln (res);
		foreach (p; ans)
		{
			writeln (p.x + 1, ' ', p.y + 1);
		}
	}
}

import std.stdio;
import std.math;
import std.array;
import std.algorithm;

// build graph
// add a path to each other with the difference price
// add a path to a node zero representing default costs
// find the MST
// print the mst starting with 0.

long cdiff(char[] a, char[] b){
  long sum = 0;
  foreach(i,c;a){
    if(b[i] != c){
      sum++;
    }
  }
  return sum;
}

class Graph{
  char[][] original_nodes;
  long[][] edges;
  size_t vertex;

  void build_with(char[][] nodes, int n, int m, int k, int w){
    this.vertex = 1 + nodes.count;
    this.original_nodes ~= [[' ']];
    this.original_nodes ~= nodes;
    this.edges = new long[][](this.vertex,this.vertex);

    for(size_t i = 0; i < this.original_nodes.length; i++){
      for(size_t j = i; j < this.original_nodes.length; j++){
        if(i == j){
          this.edges[i][i] = -1;
        } else {
          if(i == 0){
            this.edges[0][j] = n*m;
            this.edges[j][0] = n*m;
          } else {
            auto diff = cdiff(original_nodes[i],original_nodes[j]);
            this.edges[i][j] = diff*w;
            this.edges[j][i] = diff*w;
          }
        }
      }
    }
  }
}

class UnionFind{
  size_t[] set;
  size_t[] sz;
  this(size_t n){
    set = new size_t[n];
    sz = new size_t[n];
    for(size_t i = 0; i < n; i++){
      set[i] = i;
      sz[i] = 1;
    }
  }

  bool connected(size_t a,size_t b){
    return root(a) == root(b);
  }

  void connect(size_t a, size_t b){
    size_t ra = root(a);
    size_t rb = root(b);
    if(sz[rb] > sz[ra]){
      set[ra] = set[rb];
      sz[rb] += sz[ra];
    } else {
      set[rb] = set[ra];
      sz[ra] += sz[rb];
    }
  }

  size_t root(size_t a){
    size_t ra = set[a];
    while(ra != set[ra]){
      set[ra] = set[set[ra]];
      ra = set[ra];
    }
    return ra;
  }
}

class PQueue{
  Edge[] ctn;
  size_t size;
  this(Graph g){
    ctn ~= Edge.init;
    for(size_t i = 0; i < g.vertex; i++){
      for(size_t j = 0; j < g.vertex; j++){
        long ev = g.edges[i][j];
        if(ev != -1){
          Edge e = Edge(i,j,ev);
          ctn ~= e;
        }
      }
    }
    this.size = ctn.length;
    build_heap();
  }

  Edge delMin(){
    Edge ret = ctn[1];
    swap(ctn[1],ctn[size-1]);
    this.size--;

    fix_heap(1);

    return ret;
  }

  bool empty(){
    return this.size == 1;
  }

  void fix_heap(size_t i){
    size_t l = 2*i;
    size_t r = 2*i+1;
    size_t smalest = i;
    if(l < this.size && ctn[l].e < ctn[i].e){
      smalest = l;
    } else {
      smalest = i;
    }

    if(r < this.size && ctn[r].e < ctn[smalest].e){
      smalest = r;
    }

    if(smalest != i){
      swap(ctn[i],ctn[smalest]);
      fix_heap(smalest);
    }
  }

  void build_heap(){
    for(size_t i = this.size/2; i > 0; i--){
      fix_heap(i);
    }
  }
}

struct Edge{
  size_t v;
  size_t w;
  long e;
}

class Mst{
  Graph graph;
  Edge[] mst;
  this(Graph g){
    this.graph = g;
    build_mst(g);
  }

  void build_mst(Graph g){
    PQueue pq = new PQueue(g);
    UnionFind uf = new UnionFind(g.vertex);
    while(!pq.empty() && mst.length < g.vertex - 1){
      Edge e = pq.delMin();
      //writeln(pq.ctn);
      if(!uf.connected(e.v,e.w)){
         uf.connect(e.v,e.w);
         mst ~= e;
      }
    }
  }

  void print_with_cost(){
    auto lmst = this.mst.dup;
    auto lvls = lmst.length;
    int[] lvl = new int[lvls+1];
    Edge[] other;

    int sum = 0;
    for(int i = 0; i < lvls; i++){
      sum += lmst[i].e;
    }

    writeln(sum);

    auto ptc = lmst.length;
    //writeln(lmst);
    while(ptc > 0){
      foreach(e;lmst){
        if(e.v == 0 && lvl[e.w] == 0){
          writefln("%s %s",e.w,e.v);
          lvl[e.w]++;
          break;
        } else if(e.w == 0 && lvl[e.v] == 0){
          writefln("%s %s",e.v,e.w);
          lvl[e.v]++;
          break;
        } else if(lvl[e.v] == 0 && lvl[e.w] == 1 && e.v != 0) {
          writefln("%s %s",e.v,e.w);
          lvl[e.v]++;
          break;
        } else if(lvl[e.w] == 0 && lvl[e.v] == 1  && e.w != 0){
          writefln("%s %s",e.w,e.v);
          lvl[e.w]++;
          break;
        }
      }
      ptc--;
    }
    //writeln(lvl);

//     writeln(sum);
//     for(int i = 0; i < lvls; i++){
//       Edge e = lmst[i];
//       if(e.v == 0 || e.w == 0){
//         if(e.v == 0){
//           writefln("%s %s",e.w,e.v);
//           full ~= e.w;
//         } else {
//           writefln("%s %s",e.v,e.w);
//           full ~= e.v;
//         }
//       } else {
//         other += e;
//       }
//     }
//     writeln(lmst);
//     foreach(o;other){
//       if(lvl[e.v] == 1){
//
//       } else {
//
//       }
//     }
  }
}

void main(){
  int n,m,k,w;
  readf("%s %s %s %s\n",&n,&m,&k,&w);

  char[][] d = new char[][](k,m*n);
  for(int i = 0; i < k; i++){
    for(int j = 0; j < m*n; j++){
      char c = '\n';
      while(c == '\n'){
        readf("%c",&c);
      }
      d[i][j] = c;
    }
  }
  Graph g = new Graph();
  g.build_with(d,n,m,k,w);

  Mst mst = new Mst(g);

  mst.print_with_cost();
}

import std.algorithm;
import std.array;
import std.container;
import std.conv;
import std.exception;
import std.functional;
import std.math;
import std.numeric;
import std.range;
import std.stdio;
import std.string;
import std.typecons;
import core.bitop;

immutable int NA = -1;

void main ()
{
	int n, m, k, w;
	while (readf (" %s %s %s %s ", &n, &m, &k, &w) > 0)
	{
		auto a = new string [] [k];
		foreach (u; 0..k)
		{
			foreach (i; 0..n)
			{
				a[u] ~= readln ().strip ();
			}
		}

		auto d = new int [] [] (k, k);
		foreach (u; 0..k)
		{
			d[u][u] = 0;
			foreach (v; 0..u)
			{
				int cur = 0;
				foreach (i; 0..n)
				{
					foreach (j; 0..m)
					{
						cur += (a[u][i][j] !=
						    a[v][i][j]);
					}
				}
				d[u][v] = cur * w;
				d[v][u] = cur * w;
			}
		}

		long res = n * m;
		auto b = new bool [k];
		alias pair = Tuple !(int, "x", int, "y");
		auto e = new pair [k];
		pair [] ans;
		int r = 0;
		b[r] = true;
		foreach (t; 0..k)
		{
			e[t] = pair (int.max, NA);
		}
		e[r] = pair (0, NA);
		ans ~= pair (r, NA);
		foreach (t; 1..k)
		{
			auto z = pair (int.max, NA);
			foreach (v; 0..k)
			{
				if (!b[v])
				{
					if (e[v].x > d[r][v])
					{
						e[v] = pair (d[r][v], r);
					}
					if (z.x > e[v].x)
					{
						z = pair (e[v].x, v);
					}
				}
			}
			assert (z.x < int.max);
			if (z.x >= n * m)
			{
				e[z.y].y = NA;
			}
			r = z.y;
			b[r] = true;
			res += e[r].x;
			ans ~= pair (r, e[r].y);
		}

		writeln (res);
		foreach (p; ans)
		{
			writeln (p.x + 1, ' ', p.y + 1);
		}
	}
}

import std.stdio;
import std.math;
import std.array;
import std.algorithm;

// build graph
// add a path to each other with the difference price
// add a path to a node zero representing default costs
// find the MST
// print the mst starting with 0.

long cdiff(char[] a, char[] b){
  long sum = 0;
  foreach(i,c;a){
    if(b[i] != c){
      sum++;
    }
  }
  return sum;
}

class Graph{
  char[][] original_nodes;
  long[][] edges;
  size_t vertex;

  void build_with(char[][] nodes, int n, int m, int k, int w){
    this.vertex = 1 + nodes.count;
    this.original_nodes ~= [[' ']];
    this.original_nodes ~= nodes;
    this.edges = new long[][](this.vertex,this.vertex);

    for(size_t i = 0; i < this.original_nodes.length; i++){
      for(size_t j = i; j < this.original_nodes.length; j++){
        if(i == j){
          this.edges[i][i] = -1;
        } else {
          if(i == 0){
            this.edges[0][j] = n*m;
            this.edges[j][0] = -1;
          } else {
            auto diff = cdiff(original_nodes[i],original_nodes[j]);
            this.edges[i][j] = diff*w;
            this.edges[j][i] = -1;
          }
        }
      }
    }
  }
}

class UnionFind{
  size_t[] set;
  size_t[] sz;
  this(size_t n){
    set = new size_t[n];
    sz = new size_t[n];
    for(size_t i = 0; i < n; i++){
      set[i] = i;
      sz[i] = 1;
    }
  }

  bool connected(size_t a,size_t b){
    return root(a) == root(b);
  }

  void connect(size_t a, size_t b){
    size_t ra = root(a);
    size_t rb = root(b);
    if(sz[rb] > sz[ra]){
      set[ra] = set[rb];
      sz[rb] += sz[ra];
    } else {
      set[rb] = set[ra];
      sz[ra] += sz[rb];
    }
  }

  size_t root(size_t a){
    size_t ra = set[a];
    while(ra != set[ra]){
      set[ra] = set[set[ra]];
      ra = set[ra];
    }
    return ra;
  }
}

class PQueue{
  Edge[] ctn;
  size_t size;
  this(Graph g){
    ctn ~= Edge.init;
    for(size_t i = 0; i < g.vertex; i++){
      for(size_t j = 0; j < g.vertex; j++){
        long ev = g.edges[i][j];
        if(ev != -1){
          Edge e = Edge(i,j,ev);
          ctn ~= e;
        }
      }
    }
    this.size = ctn.length;
    build_heap();
  }

  Edge delMin(){
    Edge ret = ctn[1];
    swap(ctn[1],ctn[size-1]);
    this.size--;

    fix_heap(1);

    return ret;
  }

  bool empty(){
    return this.size == 1;
  }

  void fix_heap(size_t i){
    size_t l = 2*i;
    size_t r = 2*i+1;
    size_t smalest = i;
    if(l < this.size && ctn[l].e < ctn[i].e){
      smalest = l;
    } else {
      smalest = i;
    }

    if(r < this.size && ctn[r].e < ctn[smalest].e){
      smalest = r;
    }

    if(smalest != i){
      swap(ctn[i],ctn[smalest]);
      fix_heap(smalest);
    }
  }

  void build_heap(){
    for(size_t i = this.size/2; i > 0; i--){
      fix_heap(i);
    }
  }
}

struct Edge{
  size_t v;
  size_t w;
  long e;
}

class Mst{
  Graph graph;
  Edge[] mst;
  this(Graph g){
    this.graph = g;
    build_mst(g);
  }

  void build_mst(Graph g){
    PQueue pq = new PQueue(g);
    UnionFind uf = new UnionFind(g.vertex);
    while(!pq.empty() && mst.length < g.vertex - 1){
      Edge e = pq.delMin();
      //writeln(pq.ctn);
      if(!uf.connected(e.v,e.w)){
         uf.connect(e.v,e.w);
         mst ~= e;
      }
    }
  }

  void print_with_cost(){
    sort!((a,b){
      size_t ax = min(a.v,a.w);
      size_t bx = min(b.v,b.w);
      return ax < bx;
    })(this.mst);
    long sum = 0;
    foreach(e;this.mst){
      sum += e.e;
    }
    size_t[] lvl = new size_t[this.mst.length+1];

    writeln(sum);
    foreach(e;this.mst){
      auto v = min(e.v,e.w);
      auto w = max(e.v,e.w);
      if(v == 0){
        lvl[w]++;
        writefln("%s %s",w,v);
      } else {
        if(lvl[v] == 0){
          lvl[v]++;
          writefln("%s %s",v,w);
        } else {
          lvl[w]++;
          writefln("%s %s",w,v);
        }
      }
    }
  }
}

void main(){
  int n,m,k,w;
  readf("%s %s %s %s\n",&n,&m,&k,&w);

  char[][] d = new char[][](k,m*n);
  for(int i = 0; i < k; i++){
    for(int j = 0; j < m*n; j++){
      char c = '\n';
      while(c == '\n'){
        readf("%c",&c);
      }
      d[i][j] = c;
    }
  }
  Graph g = new Graph();
  g.build_with(d,n,m,k,w);

  Mst mst = new Mst(g);

  mst.print_with_cost();
}

import std.stdio;
import std.math;
import std.array;
import std.algorithm;

// build graph
// add a path to each other with the difference price
// add a path to a node zero representing default costs
// find the MST
// print the mst starting with 0.

long cdiff(char[] a, char[] b){
  long sum = 0;
  foreach(i,c;a){
    if(b[i] != c){
      sum++;
    }
  }
  return sum;
}

class Graph{
  char[][] original_nodes;
  long[][] edges;
  size_t vertex;

  void build_with(char[][] nodes, int n, int m, int k, int w){
    this.vertex = 1 + nodes.count;
    this.original_nodes ~= [[' ']];
    this.original_nodes ~= nodes;
    this.edges = new long[][](this.vertex,this.vertex);

    for(size_t i = 0; i < this.original_nodes.length; i++){
      for(size_t j = i; j < this.original_nodes.length; j++){
        if(i == j){
          this.edges[i][i] = -1;
        } else {
          if(i == 0){
            this.edges[0][j] = n*m;
            this.edges[j][0] = n*m;
          } else {
            auto diff = cdiff(original_nodes[i],original_nodes[j]);
            this.edges[i][j] = diff*w;
            this.edges[j][i] = diff*w;
          }
        }
      }
    }
  }
}

class UnionFind{
  size_t[] set;
  size_t[] sz;
  this(size_t n){
    set = new size_t[n];
    sz = new size_t[n];
    for(size_t i = 0; i < n; i++){
      set[i] = i;
      sz[i] = 1;
    }
  }

  bool connected(size_t a,size_t b){
    return root(a) == root(b);
  }

  void connect(size_t a, size_t b){
    size_t ra = root(a);
    size_t rb = root(b);
    if(sz[rb] > sz[ra]){
      set[ra] = set[rb];
      sz[rb] += sz[ra];
    } else {
      set[rb] = set[ra];
      sz[ra] += sz[rb];
    }
  }

  size_t root(size_t a){
    size_t ra = set[a];
    while(ra != set[ra]){
      set[ra] = set[set[ra]];
      ra = set[ra];
    }
    return ra;
  }
}

class PQueue{
  Edge[] ctn;
  size_t size;
  this(Graph g){
    ctn ~= Edge.init;
    for(size_t i = 0; i < g.vertex; i++){
      for(size_t j = 0; j < g.vertex; j++){
        long ev = g.edges[i][j];
        if(ev != -1){
          Edge e = Edge(i,j,ev);
          ctn ~= e;
        }
      }
    }
    this.size = ctn.length;
    build_heap();
  }

  Edge delMin(){
    Edge ret = ctn[1];
    swap(ctn[1],ctn[size-1]);
    this.size--;

    fix_heap(1);

    return ret;
  }

  bool empty(){
    return this.size == 1;
  }

  void fix_heap(size_t i){
    size_t l = 2*i;
    size_t r = 2*i+1;
    size_t smalest = i;
    if(l < this.size && ctn[l].e < ctn[i].e){
      smalest = l;
    } else {
      smalest = i;
    }

    if(r < this.size && ctn[r].e < ctn[smalest].e){
      smalest = r;
    }

    if(smalest != i){
      swap(ctn[i],ctn[smalest]);
      fix_heap(smalest);
    }
  }

  void build_heap(){
    for(size_t i = this.size/2; i > 0; i--){
      fix_heap(i);
    }
  }
}

struct Edge{
  size_t v;
  size_t w;
  long e;
}

class Mst{
  Graph graph;
  Edge[] mst;
  this(Graph g){
    this.graph = g;
    build_mst(g);
  }

  void build_mst(Graph g){
    PQueue pq = new PQueue(g);
    UnionFind uf = new UnionFind(g.vertex);
    while(!pq.empty() && mst.length < g.vertex - 1){
      Edge e = pq.delMin();
      //writeln(pq.ctn);
      if(!uf.connected(e.v,e.w)){
         uf.connect(e.v,e.w);
         mst ~= e;
      }
    }
  }

  void print_with_cost(){
    //writeln(this.graph.edges);
    //writeln(this.graph.original_nodes);
    //writefln("%s",this.mst.length);
    long[2][] pt;
    long sum;

    foreach(e;this.mst){
      if(e.v == 0 || e.w == 0){
        size_t v;
        if(e.v == 0){
          v = e.w;
        } else {
          v = e.v;
        }
        pt ~= [v,0];
        sum += e.e;
      } else {
        pt ~= [e.v,e.w];
        sum += e.e;
      }
    }
    writeln(sum);
    foreach(p;pt){
      writefln("%s %s",p[0],p[1]);
    }
  }
}

void main(){
  int n,m,k,w;
  readf("%s %s %s %s\n",&n,&m,&k,&w);

  char[][] d = new char[][](k,m*n);
  for(int i = 0; i < k; i++){
    for(int j = 0; j < m*n; j++){
      char c = '\n';
      while(c == '\n'){
        readf("%c",&c);
      }
      d[i][j] = c;
    }
  }
  Graph g = new Graph();
  g.build_with(d,n,m,k,w);

  Mst mst = new Mst(g);

  mst.print_with_cost();
}

import std.stdio;
import std.math;
import std.array;
import std.algorithm;

// build graph
// add a path to each other with the difference price
// add a path to a node zero representing default costs
// find the MST
// print the mst starting with 0.

long cdiff(char[] a, char[] b){
  long sum = 0;
  foreach(i,c;a){
    if(b[i] != c){
      sum++;
    }
  }
  return sum;
}

class Graph{
  char[][] original_nodes;
  long[][] edges;
  size_t vertex;

  void build_with(char[][] nodes, int n, int m, int k, int w){
    this.vertex = 1 + nodes.count;
    this.original_nodes ~= [[' ']];
    this.original_nodes ~= nodes;
    this.edges = new long[][](this.vertex,this.vertex);

    for(size_t i = 0; i < this.original_nodes.length; i++){
      for(size_t j = i; j < this.original_nodes.length; j++){
        if(i == j){
          this.edges[i][i] = -1;
        } else {
          if(i == 0){
            this.edges[0][j] = n*m;
            this.edges[j][0] = n*m;
          } else {
            auto diff = cdiff(original_nodes[i],original_nodes[j]);
            this.edges[i][j] = diff*w;
            this.edges[j][i] = diff*w;
          }
        }
      }
    }
  }
}

class UnionFind{
  size_t[] set;
  size_t[] sz;
  this(size_t n){
    set = new size_t[n];
    sz = new size_t[n];
    for(size_t i = 0; i < n; i++){
      set[i] = i;
      sz[i] = 1;
    }
  }

  bool connected(size_t a,size_t b){
    return root(a) == root(b);
  }

  void connect(size_t a, size_t b){
    size_t ra = root(a);
    size_t rb = root(b);
    if(sz[rb] > sz[ra]){
      set[ra] = set[rb];
      sz[rb] += sz[ra];
    } else {
      set[rb] = set[ra];
      sz[ra] += sz[rb];
    }
  }

  size_t root(size_t a){
    size_t ra = set[a];
    while(ra != set[ra]){
      set[ra] = set[set[ra]];
      ra = set[ra];
    }
    return ra;
  }
}

class PQueue{
  Edge[] ctn;
  size_t size;
  this(Graph g){
    ctn ~= Edge.init;
    for(size_t i = 0; i < g.vertex; i++){
      for(size_t j = 0; j < g.vertex; j++){
        long ev = g.edges[i][j];
        if(ev != -1){
          Edge e = Edge(i,j,ev);
          ctn ~= e;
        }
      }
    }
    this.size = ctn.length;
    build_heap();
  }

  Edge delMin(){
    Edge ret = ctn[1];
    swap(ctn[1],ctn[size-1]);
    this.size--;

    fix_heap(1);

    return ret;
  }

  bool empty(){
    return this.size == 1;
  }

  void fix_heap(size_t i){
    size_t l = 2*i;
    size_t r = 2*i+1;
    size_t smalest = i;
    if(l < this.size && ctn[l].e < ctn[i].e){
      smalest = l;
    } else {
      smalest = i;
    }

    if(r < this.size && ctn[r].e < ctn[smalest].e){
      smalest = r;
    }

    if(smalest != i){
      swap(ctn[i],ctn[smalest]);
      fix_heap(smalest);
    }
  }

  void build_heap(){
    for(size_t i = this.size/2; i > 0; i--){
      fix_heap(i);
    }
  }
}

struct Edge{
  size_t v;
  size_t w;
  long e;
}

class Mst{
  Graph graph;
  Edge[] mst;
  this(Graph g){
    this.graph = g;
    build_mst(g);
  }

  void build_mst(Graph g){
    PQueue pq = new PQueue(g);
    UnionFind uf = new UnionFind(g.vertex);
    while(!pq.empty() && mst.length < g.vertex - 1){
      Edge e = pq.delMin();
      //writeln(pq.ctn);
      if(!uf.connected(e.v,e.w)){
         uf.connect(e.v,e.w);
         mst ~= e;
      }
    }
  }

  void print_with_cost(){
    sort!((a,b){
      size_t ax = min(a.v,a.w);
      size_t bx = min(b.v,b.w);
      return ax < bx;
    })(this.mst);
    long sum = 0;
    foreach(e;this.mst){
      sum += e.e;
    }
    size_t[] lvl = new size_t[this.mst.length+1];

    writeln(sum);
    foreach(e;this.mst){
      if(lvl[e.v] == 0){
        lvl[e.v]++;
        writefln("%s %s",e.v,e.w);
      } else {
        lvl[e.w]++;
        writefln("%s %s",e.w,e.v);
      }
      //writeln(lvl);
    }
  }
}

void main(){
  int n,m,k,w;
  readf("%s %s %s %s\n",&n,&m,&k,&w);

  char[][] d = new char[][](k,m*n);
  for(int i = 0; i < k; i++){
    for(int j = 0; j < m*n; j++){
      char c = '\n';
      while(c == '\n'){
        readf("%c",&c);
      }
      d[i][j] = c;
    }
  }
  Graph g = new Graph();
  g.build_with(d,n,m,k,w);

  Mst mst = new Mst(g);

  mst.print_with_cost();
}