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 = 998244353;
//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 main()
{
	auto q = RD!int;
	auto ans = new bool[](q);
	foreach (qi; 0..q)
	{
		auto n = RD!int;
		auto m = RD;
		auto tlh = new long[][](n);
		foreach (i; 0..n)
		{
			tlh[i] = [RD, RD, RD];
		}

		bool ok = true;
		long t, h = m, l = m;
		foreach (i; 0..n)
		{
			auto d = tlh[i][0] - t;
			l = max(tlh[i][1], l-d);
			h = min(tlh[i][2], h+d);
			debug writeln("i:", i, " l:", l, " h:", h);
			if (l > tlh[i][2] || h < tlh[i][1])
			{
				ok = false;
				break;
			}
			t = tlh[i][0];
		}
		ans[qi] = ok;
	}
	foreach (e; ans)
		writeln(e ? "YES" : "NO");
	stdout.flush;
	debug readln;
}

import std.stdio, std.conv, std.string, std.array, std.range, std.algorithm, std.container;
import std.math, std.random, std.bigint, std.datetime, std.format;
void main(string[] args){ if(args.length > 1) if(args[1] == "-debug") DEBUG = 1; solve(); }
void log()(){ writeln(""); } void log(T, A ...)(T t, lazy A a){ if(DEBUG) write(t, " "), log(a); } bool DEBUG = 0;
string rstring(){ static string[] ss; while(!ss.length) ss = readln.chomp.split; string res = ss[0]; ss.popFront; return res; }
T rtype(T)(){ return rstring.to!T; } alias rint = rtype!int, rlong = rtype!long, rreal = rtype!real;
T[] rtypes(T)(int n){ return n.iota.map!(i => rtype!T()).array; } alias rint = rtypes!int, rlong = rtypes!long, rreal = rtypes!real;
T[][] rtypess(T)(int n, int m){ return n.iota.map!(i => rtypes!T(m)).array; } alias rint = rtypess!int, rlong = rtypess!long, rreal = rtypess!real;
T chmin(T)(ref T x, T y){ if(x > y) x = y; return x; } T chmax(T)(ref T x, T y){ if(x < y) x = y; return x; }

// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- //

void solve(){
	A: foreach(_; 0 .. rint){
		int n = rint;
		long m = rlong;
		S[] as;
		foreach(i; 0 .. n) as ~= S(rlong, rlong, rlong);
		// as is sorted.
		log("n:", n, "m:", m, "as:", as);

		long t = 0, l = m, r = m;
		foreach(a; as){
			log("t:", t, "l:", l, "r:", r);
			l = max(l - (a.t - t), a.l);
			r = min(r + (a.t - t), a.r);
			if(l > r){
				"NO".writeln;
				continue A;
			}
			t = a.t;
		}
		log("t:", t, "l:", l, "r:", r);
		"YES".writeln;
	}
}
struct S{
	long t, l, r;

}

import std.container;
import std.algorithm;
import std.range;
import std.array;
import std.stdio;
import std.utf;
import std.math;
import std.typecons;

struct Interval
{
  long l, h;

  bool empty()
  {
    return l > h;
  }
}

Interval intersect(Interval a, Interval b)
{
  return Interval(max(a.l, b.l), min(a.h, b.h));
}

struct Customer
{
  long t;
  Interval i;
}

alias type = multi;
struct TestCase
{
  mixin prettyPrinting;

  long n, m;
  @("n") Customer[] customers;

  void solve(long tc = -1)
  {
    if (tc == 1)
      logSym!(this);
    long lastTime = 0;
    Interval currentInterval = Interval(m, m);
    foreach(customer; customers)
      {
        with(customer)
          {
            auto elapsedTime = t - lastTime;
            currentInterval.l -= elapsedTime;
            currentInterval.h += elapsedTime;
            currentInterval = intersect(currentInterval, i);
            if (currentInterval.empty)
              break;
            lastTime = t;
          }
      }
    if (currentInterval.empty)
      {
        writeln("NO");
      }
    else
      {
        writeln("YES");
      }
  }
}

mixin template prettyPrinting()
{
  string toString()
  {
    alias structType = typeof(this);
    auto res = appender!(string)();
    res.put(structType.stringof);
    res.put("(");
    static foreach(fieldName; FieldNameTuple!structType)
      {
        res.put(text(" ", fieldName, ": ", mixin(fieldName)));
      }
    res.put(" )");
    res.put("\n");
    return res[];
  }
}

struct Graph(N)
{
  size_t size;
  this(S)(S size)
  {
    adjacencyList.length = cast(size_t) size;
    this.size = cast(size_t) size;
    this.visited = makeSlice!bool(size);
  }
  N[][] adjacencyList;
  alias ne = neighbours;
  N[] neighbours(N n)
  {
    return adjacencyList.at(n);
  }
  alias bcon = biconnect;
  void biconnect(N a, N b)
  {
    adjacencyList.at(a) ~= b;
    adjacencyList.at(b) ~= a;
  }
  alias con = connect;
  void connect(N a, N b)
  {
    adjacencyList.at(a) ~= b;
  }
  void connect(R)(R edges)
  {
    foreach(ref edge; edges)
      {
        connect(edge[0], edge[1]);
      }
  }
  void biconnect(R)(R edges)
  {
    foreach(ref edge; edges)
      {
        biconnect(edge[0], edge[1]);
      }
  }
  alias deg = degree!long;
  auto degree(T)(N a)
  {
    return cast(T) adjacencyList.at(a).length;
  }

  auto visited = new bool[0];
  void dfs(Visitor)(long startNode)
  {
    auto visitor = Visitor.init;
    void internalDfs(long node)
    {
      visited.set(node, true);
      static if (is(typeof({visitor.n = node;})))
        visitor.n = node;
      static if (is(typeof({visitor.pre;})))
        visitor.pre;
      foreach(w; ne(node))
        if (!visited.at(w))
          {
            static if (is(typeof({visitor.w = w;})))
              visitor.w = w;
            static if (is(typeof(visitor.pren)))
              visitor.pren;
            internalDfs(w);
            static if (is(typeof(visitor.postn)))
              visitor.postn;
          }
      static if (is(typeof(visitor.post)))
        visitor.post;
    }
    internalDfs(startNode);
  }
  void dfs(long startNode)
  {
    struct DefVisitor {}
    dfs!DefVisitor(startNode);
  }
}

DList!string _words;

template baseType(W)
{
  static if (isDynamicArray!W)
    alias baseType = baseType!(typeof((delegate() {W w; return w[0];})()));
  else
    alias baseType = W;
}

auto makeSlice(E, W, T...)(W size, T otherSizes)
{
  static if (T.length == 0)
    {
      E[] res;
      res.length = cast(size_t) size;
      return res;
    }
  else
    {
      typeof(makeSlice!E(otherSizes))[] res;
      res.length = cast(size_t) size;
      foreach(ref row; res)
        row = makeSlice!E(otherSizes);
      return res;
    }
}

void read(T...)(ref T t)
{
  void basicTypeRead(W)(ref W w)
  {
    import std.stdio: readln;
    while(_words.empty)
      {
        import std.array: split;
        foreach(word; readln.split)
          {
            _words.insertBack(word);
          }
      }
    import std.conv: to;
    string word = _words.front;
    _words.removeFront;
    w = to!W(word);
  }
  void iterableRead(W)(ref W w)
  {
    foreach(ref element; w)
      read(element);
  }
  void tupleRead(W)(ref W w)
  {
    static foreach(j; 0 .. W.length)
      read(w[j]);
  }
  void structRead(W)(ref W readStruct)
  {
    static foreach(fieldName; FieldNameTuple!W)
      {
        with(readStruct)
          {
            alias fieldSymbol = mixin(W.stringof, ".", fieldName);
            alias typeOfField = typeof(mixin(fieldName));
            static if (hasUDA!(fieldSymbol, string))
              {
                static assert(isDynamicArray!(typeOfField)
                              , " A field with dimension initialization UDA must be a dynamic array.");
                enum uda = getUDAs!(fieldSymbol, string)[0];
                mixin(fieldName) = mixin(q{makeSlice!(baseType!typeOfField)(}, uda, q{)});
              }
            else static if (isDynamicArray!typeOfField && !is(typeOfField == string))
              {
                pragma(msg, "Warning: You probably want to add dimension to input ", fieldName);
              }
            read(mixin(fieldName));
          }
      }
  }
  static foreach(i; 0 .. T.length)
    {
      static if (isBasicType!(T[i]) || is(T[i] == string))
        basicTypeRead(t[i]);
      else static if (is(typeof({foreach(ref e; t[i]){}})))
        iterableRead(t[i]);
      else static if (isTuple!(T[i]))
        tupleRead(t[i]);
      else static if (isAggregateType!(T[i]))
        structRead(t[i]);
    }
}

auto next(T)()
{
  T t;
  read(t);
  return t;
}

size_t ind(T)(T t)
{
  return cast(size_t)t;
}

ref auto at(R, I)(ref R r, I i)
{
  return r[cast(size_t)i];
}

void set(R, I, V)(ref R r, I i, V v)
{
  r[cast(size_t)i] = v;
}

import std.conv;
import std.traits;
import std.meta;
int _loglevel = -1;
void _log(string functionName, argSeq...)()
{
  foreach(i; 0 .. _loglevel * 4)
    write(' ');
  write(functionName);
  static foreach(arg; argSeq)
    {
      write(" ", arg.stringof, " = ", arg);
    }
  writeln;
}
enum logCall =
  q{
    debug
    {
     {
     _loglevel++;
     alias _parameterTuple = ParameterIdentifierTuple!(mixin(split(__FUNCTION__, ".").back));
     static if (_parameterTuple.length > 0)
       mixin(`_log!(__FUNCTION__, `, [_parameterTuple].joiner(", ").array, `);`);
     else
       _log!(__FUNCTION__);
      }
     foreach(i; 0 .. _loglevel * 4) write(' ');
     writeln('{');
     scope(exit)
       {
         foreach(i; 0 .. _loglevel * 4) write(' ');
         writeln('}');
         _loglevel--;
       }
    }
};

void logSym(S...)(int line = __LINE__, string file = __FUNCTION__)
{
  debug
    {
      foreach(i; 0 .. _loglevel * 4) write(' ');
      write(file, "(", line, "):");
      static foreach(s; S)
        write(" ", s.stringof, " = ", s);
      writeln;

    }
}

Array!E makeArray(E, S)(S size, lazy E value)
{
  auto a = Array!E();
  a.length = cast(size_t) size;
  foreach(ref ai; a)
    ai = value();
  return a;
}
Array!E makeArray(E, S)(S size)
{
  auto a = Array!E();
  a.length = cast(size_t) size;
  return a;
}

template mem(alias F)
{
  ReturnType!F[Tuple!(Parameters!F)] table;
  ReturnType!F mem(Parameters!F args)
  {
    return table.require(tuple(args), F(args));
  }
}

string input(string names, string type = "long")
{
  return text(type, " ", names, "; read(", names, ");");
}

auto pmod(T, W)(T t, W w)
{
  return (t%w + w) % w;
}

void rep(S, F)(F f, S times)
{
  static if (is(typeof(f(i))))
    foreach(i; 0 .. times)
      f(i);
  else
    foreach(i; 0 .. times)
      f();
}

void multi()
{
  foreach(tc; 0 .. next!long)
    next!TestCase.solve(tc);
}

void single()
{
  auto tc = next!TestCase;
  tc.solve;
}

void main()
{
  type;
}

import std.stdio, std.conv, std.string, std.array, std.range, std.algorithm, std.container;
import std.math, std.random, std.bigint, std.datetime, std.format;
void main(string[] args){ if(args.length > 1) if(args[1] == "-debug") DEBUG = 1; solve(); }
void log()(){ writeln(""); } void log(T, A ...)(T t, lazy A a){ if(DEBUG) write(t, " "), log(a); } bool DEBUG = 0;
string rstring(){ static string[] ss; while(!ss.length) ss = readln.chomp.split; string res = ss[0]; ss.popFront; return res; }
T rtype(T)(){ return rstring.to!T; } alias rint = rtype!int, rlong = rtype!long, rreal = rtype!real;
T[] rtypes(T)(int n){ return n.iota.map!(i => rtype!T()).array; } alias rint = rtypes!int, rlong = rtypes!long, rreal = rtypes!real;
T[][] rtypess(T)(int n, int m){ return n.iota.map!(i => rtypes!T(m)).array; } alias rint = rtypess!int, rlong = rtypess!long, rreal = rtypess!real;
T chmin(T)(ref T x, T y){ if(x > y) x = y; return x; } T chmax(T)(ref T x, T y){ if(x < y) x = y; return x; }

// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- //

void solve(){
	A: foreach(_; 0 .. rint){
		int n = rint;
		long m = rlong;
		S[] as;
		foreach(i; 0 .. n) as ~= S(rlong, rlong, rlong);
		// as is sorted.

		long t = m, l = 0, r = 0;
		foreach(a; as){
			l = max(l - (a.t - t), a.l);
			r = min(r + (a.t - t), a.r);
			if(l > r){
				"NO".writeln;
				continue A;
			}
			t = a.t;
		}
		"YES".writeln;
	}
}
struct S{
	long t, l, r;

}

import std.stdio, std.conv, std.string, std.array, std.range, std.algorithm, std.container;
import std.math, std.random, std.bigint, std.datetime, std.format;
void main(string[] args){ if(args.length > 1) if(args[1] == "-debug") DEBUG = 1; solve(); }
void log()(){ writeln(""); } void log(T, A ...)(T t, lazy A a){ if(DEBUG) write(t, " "), log(a); } bool DEBUG = 0;
string rstring(){ static string[] ss; while(!ss.length) ss = readln.chomp.split; string res = ss[0]; ss.popFront; return res; }
T rtype(T)(){ return rstring.to!T; } alias rint = rtype!int, rlong = rtype!long, rreal = rtype!real;
T[] rtypes(T)(int n){ return n.iota.map!(i => rtype!T()).array; } alias rint = rtypes!int, rlong = rtypes!long, rreal = rtypes!real;
T[][] rtypess(T)(int n, int m){ return n.iota.map!(i => rtypes!T(m)).array; } alias rint = rtypess!int, rlong = rtypess!long, rreal = rtypess!real;
T chmin(T)(ref T x, T y){ if(x > y) x = y; return x; } T chmax(T)(ref T x, T y){ if(x < y) x = y; return x; }

// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- //

void solve(){
	A: foreach(_; 0 .. rint){
		int n = rint;
		long m = rlong;
		S[] as;
		foreach(i; 0 .. n) as ~= S(rlong, rlong, rlong);
		// as is sorted.

		long t = m, l = 0, r = 0;
		foreach(a; as){
			l = max(l - (a.t - t), a.l);
			r = min(r + (a.t - t), a.r);
			if(l > r){
				"NO".writeln;
				continue A;
			}
		}
		"YES".writeln;
	}
}
struct S{
	long t, l, r;
}


module main;
import std.bigint,std.container,std.array,std.algorithm,std.conv,
	std.functional,std.math,std.numeric,std.string,std.range,std.complex,
	std.typecons,std.regex,std.random,std.uni,std.traits,std.variant,
	std.stdio,std.bitmanip;
import core.stdc.stdio : freopen;
alias BitArray bitset;
alias RedBlackTree Rbt;
alias redBlackTree rbt;
alias BigInt big;
alias pair!(int,int) pii;
alias pair!(long,long) pll;
alias BoyerMooreFinder strfind;
alias make_pair mp;
alias binary_search bins;
alias orient_square orsq;
immutable int mod=10^^9+7;
pure nothrow
{
	T lcm (T)(auto ref T a,auto ref T b)
	{
		return a/gcd(a,b)*b;
	}
	X binpow(X,Y)(X base,Y exp)
		if(is(typeof(exp&1)))
	{
		if(exp<0)return X(0);
		X res=X(1);
		while(exp>0)
		{
			if(exp&1)res*=base;
			base*=base;
			exp>>=1;
		}
		return res;
	}
	auto binpow(X,Y,Z)(X base,Y exp,in Z mm)
		if(is(typeof(exp&1)))
	{
		if(mm==0) return binpow(base,exp);
		if(exp<0)return X(0);
		auto res=X(1)%mm;
		while(exp>0)
		{
			if(exp&1)res=(res*base)%mm;
			base*=base;
			base%=mm;
			exp>>=1;
		}
		return res;
	}
	@property X sqr(X)(in X a_) {return a_*a_;}
	@property X cub(X)(in X a_) {return a_*a_*a_;}
	size_t lowb(T,X)(in T a,auto ref X g)
		if(isRandomAccessRange!T && hasLength!T && is(typeof(g<a[0])==bool))
	{
		size_t l=0,r=a.length;
		while(r-l>1)
		{
			auto m=(l+r)>>1;
			if(!(a[m]<g))r=m;
			else l=m;
		}
		return (!(a[l]<g))?l:r;
	}
	size_t upb(T,X)(in T a,auto ref X g)
		if(isRandomAccessRange!T && hasLength!T && is(typeof(g<a[0])==bool))
	{
		size_t l=0,r=a.length;
		while(r-l>1)
		{
			auto m=(l+r)>>1;
			if(g<a[m])r=m;
			else l=m;
		}
		return (g<a[l])?l:r;
	}
	size_t binf(T,X)(in T a,auto ref X g)
		if(isRandomAccessRange!T && hasLength!T && is(typeof(g<a[0])==bool))
	{
		size_t l=0,r=a.length;
		while(r-l>1)
		{
			auto m=(l+r)>>1;
			if(!(a[m]<g))r=m;
			else l=m;
		}
		return (g==a[l])?l:a.length;
	}
	bool binary_search(T,X)(in T a,auto ref X g)
		if(isRandomAccessRange!T && hasLength!T && is(typeof(g<a[0])==bool))
	{
		return binf(a,g)!=a.length;
	}
	V foldr(R,V,T)(R range,T arg,V nach)
		if(isFunction!T && isInputRange!R && is(typeof(arg(nach,R.front))==V))
	{
		for(;!range.empty;range.popFront()) nach=arg(nach,range.front);
		return nach;
	}
	size_t countr(R,T)(R range,T fun)
		if(isFunction!T && isInputRange!R && is(typeof(fun(R.front))==bool))
	{
		size_t nach;
		for(;!range.empty;range.popFront()) nach+=fun(range.front);
		return nach;
	}
	T orient_square(T)(pair!(T,T)[] figure...)
	{
		auto n=figure.front,t=figure.front;
		figure.popFront();
		T ans=0;
		for(;!figure.empty;figure.popFront())
		{
			ans+=(figure.front.fi-t.fi)*(figure.front.se+t.se);
			t=figure.front;
		}
		return ans+(n.fi-t.fi)*(n.se+t.se);
	}
	real square(T)(pair!(T,T)[] figure...)
		if(is(typeof(figure.front*figure.front)==T))
	{
		return abs(orient_square(figure))/2.000000000000000;
	}
}
void putarr(X)(in X a,in char ch=' '){foreach(const ref i;a)write(i,ch);}
void putarr(X)(in X a,in size_t n,in size_t m)
{
	foreach(i;0..n)
	{
		foreach(j;0..m)write(a[i][j],' ');
		writeln;
	}
}
bool getarr(X)(X a,in size_t n)
{bool b=1; foreach(ref i;a[0..n])b=input(&i);return b;}
bool input(T...)(T ptrs) if (ptrs.length > 0)
{return readf(replicate(" %s", ptrs.length), ptrs)==ptrs.length;}
bool read(T...)(T ptrs) if (ptrs.length > 0)
{return readf(replicate(" %s", ptrs.length)~'\n', ptrs)==ptrs.length;}
struct pair(X,Y)
{
	X first;
	Y second;
	alias first fi;
	alias second se;
	this(X a_,Y b_){
		fi=a_;
		se=b_;
	}
	this(this){fi=fi;se=se;}
	this(A,B)(auto ref pair!(A,B) p) if(is(A:X) && is(B:Y))
	{
		fi=p.fi;
		se=p.se;
	}
	int opCmp(A,B)(in pair!(A,B) s_) const
		if(is(typeof(s_.fi<fi)==bool) && is(typeof(s_.se<se)==bool))
	{
		int cmp=0-(fi<s_.fi)+(fi>s_.fi);
		if(cmp!=0)return cmp;
		else return (0-(se<s_.se)+(se>s_.se));
	}
};
pair!(X,Y) make_pair(X,Y)(in X x_,in Y y_)
{
	pair!(X,Y) pp;
	pp.fi=x_;
	pp.se=y_;
	return pp;
}
nothrow void inf(in char* name) {freopen(name,"r",core.stdc.stdio.stdin);}
nothrow void ouf(in char* name) {freopen(name,"w",core.stdc.stdio.stdout);}
@property auto arread(T)(){return readln.split.map!(to!(T)).array;}
//split strip isAlpha isNumber isWhite isLower isUpper toLower toUpper mixin
//cumulativeFold schwartzSort multiSort partialSort heapify join filter countUntil
//---------------------------------------------------------------program beginning-----------------------------------------------------------------

void main()
{
	int n,m;
	loop:while(read(&n,&m))
	{
		auto g=new int[][m+1];
		foreach(i;1..n+1)
		{
			int k;
			input(&k);
			foreach(j;0..k)
			{
				int f;
				input(&f);
				g[f]~=i;
			}
		}
		int[int[]] q;
		foreach(i;g[1..$])
		{
			q[i.idup]++;
		}
		auto fact=(1L~iota(1L,5L*(10^^6)).array).cumulativeFold!"(a*b)%1000000007"(1L).array;
		long ans=1;
		foreach(i;q.byValue)
		{
			ans=(ans*fact[i])%mod;
		}
		/*long ans=1,t=1;
		sort(g[1..$]);
		debug foreach(i;g)writeln(i);
		foreach(i;2..m+1)
		{
			if(g[i]==g[i-1])
			{
				ans=(ans*(++t))%mod;
			}
			else t=1;
		}*/
		writeln(ans);
	}
}

module main;
import std.bigint,std.container,std.array,std.algorithm,std.conv,
	std.functional,std.math,std.numeric,std.string,std.range,std.complex,
	std.typecons,std.regex,std.random,std.uni,std.traits,std.variant,
	std.stdio,std.bitmanip;
import core.stdc.stdio : freopen;
alias BitArray bitset;
alias RedBlackTree Rbt;
alias redBlackTree rbt;
alias BigInt big;
alias pair!(int,int) pii;
alias pair!(long,long) pll;
alias BoyerMooreFinder strfind;
alias make_pair mp;
alias binary_search bins;
alias orient_square orsq;
immutable int mod=10^^9+7;
pure nothrow
{
	T lcm (T)(auto ref T a,auto ref T b)
	{
		return a/gcd(a,b)*b;
	}
	X binpow(X,Y)(X base,Y exp)
		if(is(typeof(exp&1)))
	{
		if(exp<0)return X(0);
		X res=X(1);
		while(exp>0)
		{
			if(exp&1)res*=base;
			base*=base;
			exp>>=1;
		}
		return res;
	}
	auto binpow(X,Y,Z)(X base,Y exp,in Z mm)
		if(is(typeof(exp&1)))
	{
		if(mm==0) return binpow(base,exp);
		if(exp<0)return X(0);
		auto res=X(1)%mm;
		while(exp>0)
		{
			if(exp&1)res=(res*base)%mm;
			base*=base;
			base%=mm;
			exp>>=1;
		}
		return res;
	}
	@property X sqr(X)(in X a_) {return a_*a_;}
	@property X cub(X)(in X a_) {return a_*a_*a_;}
	size_t lowb(T,X)(in T a,auto ref X g)
		if(isRandomAccessRange!T && hasLength!T && is(typeof(g<a[0])==bool))
	{
		size_t l=0,r=a.length;
		while(r-l>1)
		{
			auto m=(l+r)>>1;
			if(!(a[m]<g))r=m;
			else l=m;
		}
		return (!(a[l]<g))?l:r;
	}
	size_t upb(T,X)(in T a,auto ref X g)
		if(isRandomAccessRange!T && hasLength!T && is(typeof(g<a[0])==bool))
	{
		size_t l=0,r=a.length;
		while(r-l>1)
		{
			auto m=(l+r)>>1;
			if(g<a[m])r=m;
			else l=m;
		}
		return (g<a[l])?l:r;
	}
	size_t binf(T,X)(in T a,auto ref X g)
		if(isRandomAccessRange!T && hasLength!T && is(typeof(g<a[0])==bool))
	{
		size_t l=0,r=a.length;
		while(r-l>1)
		{
			auto m=(l+r)>>1;
			if(!(a[m]<g))r=m;
			else l=m;
		}
		return (g==a[l])?l:a.length;
	}
	bool binary_search(T,X)(in T a,auto ref X g)
		if(isRandomAccessRange!T && hasLength!T && is(typeof(g<a[0])==bool))
	{
		return binf(a,g)!=a.length;
	}
	V foldr(R,V,T)(R range,T arg,V nach)
		if(isFunction!T && isInputRange!R && is(typeof(arg(nach,R.front))==V))
	{
		for(;!range.empty;range.popFront()) nach=arg(nach,range.front);
		return nach;
	}
	size_t countr(R,T)(R range,T fun)
		if(isFunction!T && isInputRange!R && is(typeof(fun(R.front))==bool))
	{
		size_t nach;
		for(;!range.empty;range.popFront()) nach+=fun(range.front);
		return nach;
	}
	T orient_square(T)(pair!(T,T)[] figure...)
	{
		auto n=figure.front,t=figure.front;
		figure.popFront();
		T ans=0;
		for(;!figure.empty;figure.popFront())
		{
			ans+=(figure.front.fi-t.fi)*(figure.front.se+t.se);
			t=figure.front;
		}
		return ans+(n.fi-t.fi)*(n.se+t.se);
	}
	real square(T)(pair!(T,T)[] figure...)
		if(is(typeof(figure.front*figure.front)==T))
	{
		return abs(orient_square(figure))/2.000000000000000;
	}
}
void putarr(X)(in X a,in char ch=' '){foreach(const ref i;a)write(i,ch);}
void putarr(X)(in X a,in size_t n,in size_t m)
{
	foreach(i;0..n)
	{
		foreach(j;0..m)write(a[i][j],' ');
		writeln;
	}
}
bool getarr(X)(X a,in size_t n)
{bool b=1; foreach(ref i;a[0..n])b=input(&i);return b;}
bool input(T...)(T ptrs) if (ptrs.length > 0)
{return readf(replicate(" %s", ptrs.length), ptrs)==ptrs.length;}
bool read(T...)(T ptrs) if (ptrs.length > 0)
{return readf(replicate(" %s", ptrs.length)~'\n', ptrs)==ptrs.length;}
struct pair(X,Y)
{
	X first;
	Y second;
	alias first fi;
	alias second se;
	this(X a_,Y b_){
		fi=a_;
		se=b_;
	}
	this(this){fi=fi;se=se;}
	this(A,B)(auto ref pair!(A,B) p) if(is(A:X) && is(B:Y))
	{
		fi=p.fi;
		se=p.se;
	}
	int opCmp(A,B)(in pair!(A,B) s_) const
		if(is(typeof(s_.fi<fi)==bool) && is(typeof(s_.se<se)==bool))
	{
		int cmp=0-(fi<s_.fi)+(fi>s_.fi);
		if(cmp!=0)return cmp;
		else return (0-(se<s_.se)+(se>s_.se));
	}
};
pair!(X,Y) make_pair(X,Y)(in X x_,in Y y_)
{
	pair!(X,Y) pp;
	pp.fi=x_;
	pp.se=y_;
	return pp;
}
nothrow void inf(in char* name) {freopen(name,"r",core.stdc.stdio.stdin);}
nothrow void ouf(in char* name) {freopen(name,"w",core.stdc.stdio.stdout);}
@property auto arread(T)(){return readln.split.map!(to!(T)).array;}
//split strip isAlpha isNumber isWhite isLower isUpper toLower toUpper mixin
//cumulativeFold schwartzSort multiSort partialSort heapify join filter countUntil
//---------------------------------------------------------------program beginning-----------------------------------------------------------------

void main()
{
	int n,m;
	loop:while(read(&n,&m))
	{
		auto g=new int[][m+1];
		foreach(i;1..n+1)
		{
			int k;
			input(&k);
			foreach(j;0..k)
			{
				int f;
				input(&f);
				g[f]~=i;
			}
		}
		int[int[]] q;
		foreach(i;g[1..$])
		{
			q[i.idup]++;
		}
		auto fact=(1L~iota(1L,(10^^6)).array).cumulativeFold!"(a*b)%1000000007"(1L).array;
		long ans=1;
		foreach(i;q.byValue)
		{
			ans=(ans*fact[i])%mod;
		}
		/*long ans=1,t=1;
		sort(g[1..$]);
		debug foreach(i;g)writeln(i);
		foreach(i;2..m+1)
		{
			if(g[i]==g[i-1])
			{
				ans=(ans*(++t))%mod;
			}
			else t=1;
		}*/
		writeln(ans);
	}
}

module main;
import std.bigint,std.container,std.array,std.algorithm,std.conv,
	std.functional,std.math,std.numeric,std.string,std.range,std.complex,
	std.typecons,std.regex,std.random,std.uni,std.traits,std.variant,
	std.stdio,std.bitmanip;
import core.stdc.stdio : freopen;
alias BitArray bitset;
alias RedBlackTree Rbt;
alias redBlackTree rbt;
alias BigInt big;
alias pair!(int,int) pii;
alias pair!(long,long) pll;
alias BoyerMooreFinder strfind;
alias make_pair mp;
alias binary_search bins;
alias orient_square orsq;
immutable int mod=10^^9+7;
pure nothrow
{
	T lcm (T)(auto ref T a,auto ref T b)
	{
		return a/gcd(a,b)*b;
	}
	X binpow(X,Y)(X base,Y exp)
		if(is(typeof(exp&1)))
	{
		if(exp<0)return X(0);
		X res=X(1);
		while(exp>0)
		{
			if(exp&1)res*=base;
			base*=base;
			exp>>=1;
		}
		return res;
	}
	auto binpow(X,Y,Z)(X base,Y exp,in Z mm)
		if(is(typeof(exp&1)))
	{
		if(mm==0) return binpow(base,exp);
		if(exp<0)return X(0);
		auto res=X(1)%mm;
		while(exp>0)
		{
			if(exp&1)res=(res*base)%mm;
			base*=base;
			base%=mm;
			exp>>=1;
		}
		return res;
	}
	@property X sqr(X)(in X a_) {return a_*a_;}
	@property X cub(X)(in X a_) {return a_*a_*a_;}
	size_t lowb(T,X)(in T a,auto ref X g)
		if(isRandomAccessRange!T && hasLength!T && is(typeof(g<a[0])==bool))
	{
		size_t l=0,r=a.length;
		while(r-l>1)
		{
			auto m=(l+r)>>1;
			if(!(a[m]<g))r=m;
			else l=m;
		}
		return (!(a[l]<g))?l:r;
	}
	size_t upb(T,X)(in T a,auto ref X g)
		if(isRandomAccessRange!T && hasLength!T && is(typeof(g<a[0])==bool))
	{
		size_t l=0,r=a.length;
		while(r-l>1)
		{
			auto m=(l+r)>>1;
			if(g<a[m])r=m;
			else l=m;
		}
		return (g<a[l])?l:r;
	}
	size_t binf(T,X)(in T a,auto ref X g)
		if(isRandomAccessRange!T && hasLength!T && is(typeof(g<a[0])==bool))
	{
		size_t l=0,r=a.length;
		while(r-l>1)
		{
			auto m=(l+r)>>1;
			if(!(a[m]<g))r=m;
			else l=m;
		}
		return (g==a[l])?l:a.length;
	}
	bool binary_search(T,X)(in T a,auto ref X g)
		if(isRandomAccessRange!T && hasLength!T && is(typeof(g<a[0])==bool))
	{
		return binf(a,g)!=a.length;
	}
	V foldr(R,V,T)(R range,T arg,V nach)
		if(isFunction!T && isInputRange!R && is(typeof(arg(nach,R.front))==V))
	{
		for(;!range.empty;range.popFront()) nach=arg(nach,range.front);
		return nach;
	}
	size_t countr(R,T)(R range,T fun)
		if(isFunction!T && isInputRange!R && is(typeof(fun(R.front))==bool))
	{
		size_t nach;
		for(;!range.empty;range.popFront()) nach+=fun(range.front);
		return nach;
	}
	T orient_square(T)(pair!(T,T)[] figure...)
	{
		auto n=figure.front,t=figure.front;
		figure.popFront();
		T ans=0;
		for(;!figure.empty;figure.popFront())
		{
			ans+=(figure.front.fi-t.fi)*(figure.front.se+t.se);
			t=figure.front;
		}
		return ans+(n.fi-t.fi)*(n.se+t.se);
	}
	real square(T)(pair!(T,T)[] figure...)
		if(is(typeof(figure.front*figure.front)==T))
	{
		return abs(orient_square(figure))/2.000000000000000;
	}
}
void putarr(X)(in X a,in char ch=' '){foreach(const ref i;a)write(i,ch);}
void putarr(X)(in X a,in size_t n,in size_t m)
{
	foreach(i;0..n)
	{
		foreach(j;0..m)write(a[i][j],' ');
		writeln;
	}
}
bool getarr(X)(X a,in size_t n)
{bool b=1; foreach(ref i;a[0..n])b=input(&i);return b;}
bool input(T...)(T ptrs) if (ptrs.length > 0)
{return readf(replicate(" %s", ptrs.length), ptrs)==ptrs.length;}
bool read(T...)(T ptrs) if (ptrs.length > 0)
{return readf(replicate(" %s", ptrs.length)~'\n', ptrs)==ptrs.length;}
struct pair(X,Y)
{
	X first;
	Y second;
	alias first fi;
	alias second se;
	this(X a_,Y b_){
		fi=a_;
		se=b_;
	}
	this(this){fi=fi;se=se;}
	this(A,B)(auto ref pair!(A,B) p) if(is(A:X) && is(B:Y))
	{
		fi=p.fi;
		se=p.se;
	}
	int opCmp(A,B)(in pair!(A,B) s_) const
		if(is(typeof(s_.fi<fi)==bool) && is(typeof(s_.se<se)==bool))
	{
		int cmp=0-(fi<s_.fi)+(fi>s_.fi);
		if(cmp!=0)return cmp;
		else return (0-(se<s_.se)+(se>s_.se));
	}
};
pair!(X,Y) make_pair(X,Y)(in X x_,in Y y_)
{
	pair!(X,Y) pp;
	pp.fi=x_;
	pp.se=y_;
	return pp;
}
nothrow void inf(in char* name) {freopen(name,"r",core.stdc.stdio.stdin);}
nothrow void ouf(in char* name) {freopen(name,"w",core.stdc.stdio.stdout);}
@property auto arread(T)(){return readln.split.map!(to!(T)).array;}
//split strip isAlpha isNumber isWhite isLower isUpper toLower toUpper mixin
//cumulativeFold schwartzSort multiSort partialSort heapify join filter countUntil
//---------------------------------------------------------------program beginning-----------------------------------------------------------------

void main()
{
	int n,m;
	loop:while(read(&n,&m))
	{
		auto g=new int[][m+1];
		foreach(i;1..n+1)
		{
			int k;
			input(&k);
			foreach(j;0..k)
			{
				int f;
				input(&f);
				g[f]~=i;
			}
		}
		/*int[int[]] q;
		foreach(i;g)
		{
			if(i.length)q[i.idup]++;
		}
		auto fact=(1L~iota(1L,5L*(10^^5)+1).array).cumulativeFold!"(a*b)%1000000007"(1L).array;
		long ans=1;
		foreach(i;q.byValue)
		{
			ans=(ans*fact[i])%mod;
		}*/
		long ans=1,t=1;
		sort(g[1..$]);
		debug foreach(i;g)writeln(i);
		foreach(i;2..m+1)
		{
			if(g[i]==g[i-1])
			{
				ans=(ans*(++t))%mod;
			}
			else t=1;
		}
		writeln(ans);
	}
}

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

void main()
{
    int n, m;
    readf("%s %s", &n, &m);
    readln;

    auto idx = new int[] (m+1);
    int nxtid = 1;
    foreach (_; 0 .. n) {
        auto nrs = readln.chomp.split.map!(to!int).dropOne.array;

        int[int] cnt;

        foreach (e; nrs) { cnt[e] += 1; }

        int[][int] groups;
        foreach (p; cnt.byKeyValue) {
            groups[p.value] ~= p.key;
        }

        debug { groups.writeln; }

        foreach (arr; groups.values) {
            arr.schwartzSort!(x => idx[x]);

            foreach (p, n; lockstep(arr, arr.dropOne)) {
                bool inc = idx[p] != idx[n];

                idx[p] = nxtid;

                if (inc) { nxtid += 1; }
            }

            idx[arr.back] = nxtid;

            ++nxtid;
        }

        debug { idx.dropOne.writeln; }
    }

    debug { idx.writeln; }

    auto grouped = idx.dropOne.sort.group.map!(t => t[1]);

    debug { grouped.writeln; }

    immutable int MD = 10 ^^ 9 + 7;

    auto fac = new int[] (m+1);
    fac[0] = 1;
    foreach (i; 1 .. m+1) { fac[i] = fac[i-1].to!long * i % MD; }

    auto ans = grouped.map!(x => fac[x])
        .fold!((x, y) => (x.to!long * y % MD).to!int)(1);

    ans.writeln;
}

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

immutable int mod = 10 ^^ 9 + 7;

void main ()
{
	int n;
	int m;
	while (readf (" %s %s", &n, &m) > 0)
	{
		readln;
		auto hash = new ulong [m];
		foreach (i; 0..n)
		{
			int [int] num;
			foreach (type; readln.split.drop (1).map !(to !(int)))
			{
				num[type] += 1;
			}
			alias Pair = Tuple !(int, q{num}, int, q{type});
			Pair [] a;
			a.reserve (num.length);
			foreach (key, value; num)
			{
				a ~= Pair (value, key);
			}
			sort (a);
			foreach (g; a.chunkBy !(p => p.num))
			{
				auto v = uniform !(ulong) ();
				foreach (type; g[1].map !(x => x.type))
				{
					hash[type - 1] ^= v;
				}
			}
		}
		debug {writeln (hash);}

		long res = 1;
		sort (hash);
		foreach (num; hash.group)
		{
			foreach (i; 0..num[1])
			{
				res = (res * 1L * (i + 1)) % mod;
			}
		}
		writeln (res);
	}
}

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

immutable long mod = 10^^9 + 7;

void main(){
    int N, M;
    readVars(N, M);

    auto types = new int[][M];

    foreach(i ; 0 .. N){
        auto line = readln.split.to!(int[]);

        foreach(t ; line[1 .. $]){
            types[t - 1] ~= i;
        }
    }

    foreach(i ; 0 .. types.length.to!int){
        sort(types[i]);
    }

    sort(types);

    long ans = 1, cnt = 1;

    foreach(i ; 0 .. types.length.to!int - 1){
        if (types[i] == types[i + 1]){
            cnt++;
            ans = (ans * cnt) % mod;
        } else {
            cnt = 1;
        }
    }

    writeln(ans);
}

void readVars(T...)(auto ref T args){
    auto line = readln.split;
    foreach(ref arg ; args){
        arg = line.front.to!(typeof(arg));
        line.popFront;
    }
    if(!line.empty){
        throw new Exception("args num < input num");
    }
}

module main;
import std.bigint,std.container,std.array,std.algorithm,std.conv,
	std.functional,std.math,std.numeric,std.string,std.range,std.complex,
	std.typecons,std.regex,std.random,std.uni,std.traits,std.variant,
	std.stdio,std.bitmanip;
import core.stdc.stdio : freopen;
alias BitArray bitset;
alias RedBlackTree Rbt;
alias redBlackTree rbt;
alias BigInt big;
alias pair!(int,int) pii;
alias pair!(long,long) pll;
alias BoyerMooreFinder strfind;
alias make_pair mp;
alias binary_search bins;
alias orient_square orsq;
immutable int mod=10^^9+7;
pure nothrow
{
	T lcm (T)(auto ref T a,auto ref T b)
	{
		return a/gcd(a,b)*b;
	}
	X binpow(X,Y)(X base,Y exp)
		if(is(typeof(exp&1)))
	{
		if(exp<0)return X(0);
		X res=X(1);
		while(exp>0)
		{
			if(exp&1)res*=base;
			base*=base;
			exp>>=1;
		}
		return res;
	}
	auto binpow(X,Y,Z)(X base,Y exp,in Z mm)
		if(is(typeof(exp&1)))
	{
		if(mm==0) return binpow(base,exp);
		if(exp<0)return X(0);
		auto res=X(1)%mm;
		while(exp>0)
		{
			if(exp&1)res=(res*base)%mm;
			base*=base;
			base%=mm;
			exp>>=1;
		}
		return res;
	}
	@property X sqr(X)(in X a_) {return a_*a_;}
	@property X cub(X)(in X a_) {return a_*a_*a_;}
	size_t lowb(T,X)(in T a,auto ref X g)
		if(isRandomAccessRange!T && hasLength!T && is(typeof(g<a[0])==bool))
	{
		size_t l=0,r=a.length;
		while(r-l>1)
		{
			auto m=(l+r)>>1;
			if(!(a[m]<g))r=m;
			else l=m;
		}
		return (!(a[l]<g))?l:r;
	}
	size_t upb(T,X)(in T a,auto ref X g)
		if(isRandomAccessRange!T && hasLength!T && is(typeof(g<a[0])==bool))
	{
		size_t l=0,r=a.length;
		while(r-l>1)
		{
			auto m=(l+r)>>1;
			if(g<a[m])r=m;
			else l=m;
		}
		return (g<a[l])?l:r;
	}
	size_t binf(T,X)(in T a,auto ref X g)
		if(isRandomAccessRange!T && hasLength!T && is(typeof(g<a[0])==bool))
	{
		size_t l=0,r=a.length;
		while(r-l>1)
		{
			auto m=(l+r)>>1;
			if(!(a[m]<g))r=m;
			else l=m;
		}
		return (g==a[l])?l:a.length;
	}
	bool binary_search(T,X)(in T a,auto ref X g)
		if(isRandomAccessRange!T && hasLength!T && is(typeof(g<a[0])==bool))
	{
		return binf(a,g)!=a.length;
	}
	V foldr(R,V,T)(R range,T arg,V nach)
		if(isFunction!T && isInputRange!R && is(typeof(arg(nach,R.front))==V))
	{
		for(;!range.empty;range.popFront()) nach=arg(nach,range.front);
		return nach;
	}
	size_t countr(R,T)(R range,T fun)
		if(isFunction!T && isInputRange!R && is(typeof(fun(R.front))==bool))
	{
		size_t nach;
		for(;!range.empty;range.popFront()) nach+=fun(range.front);
		return nach;
	}
	T orient_square(T)(pair!(T,T)[] figure...)
	{
		auto n=figure.front,t=figure.front;
		figure.popFront();
		T ans=0;
		for(;!figure.empty;figure.popFront())
		{
			ans+=(figure.front.fi-t.fi)*(figure.front.se+t.se);
			t=figure.front;
		}
		return ans+(n.fi-t.fi)*(n.se+t.se);
	}
	real square(T)(pair!(T,T)[] figure...)
		if(is(typeof(figure.front*figure.front)==T))
	{
		return abs(orient_square(figure))/2.000000000000000;
	}
}
void putarr(X)(in X a,in char ch=' '){foreach(const ref i;a)write(i,ch);}
void putarr(X)(in X a,in size_t n,in size_t m)
{
	foreach(i;0..n)
	{
		foreach(j;0..m)write(a[i][j],' ');
		writeln;
	}
}
bool getarr(X)(X a,in size_t n)
{bool b=1; foreach(ref i;a[0..n])b=input(&i);return b;}
bool input(T...)(T ptrs) if (ptrs.length > 0)
{return readf(replicate(" %s", ptrs.length), ptrs)==ptrs.length;}
bool read(T...)(T ptrs) if (ptrs.length > 0)
{return readf(replicate(" %s", ptrs.length)~'\n', ptrs)==ptrs.length;}
struct pair(X,Y)
{
	X first;
	Y second;
	alias first fi;
	alias second se;
	this(X a_,Y b_){
		fi=a_;
		se=b_;
	}
	this(this){fi=fi;se=se;}
	this(A,B)(auto ref pair!(A,B) p) if(is(A:X) && is(B:Y))
	{
		fi=p.fi;
		se=p.se;
	}
	int opCmp(A,B)(in pair!(A,B) s_) const
		if(is(typeof(s_.fi<fi)==bool) && is(typeof(s_.se<se)==bool))
	{
		int cmp=0-(fi<s_.fi)+(fi>s_.fi);
		if(cmp!=0)return cmp;
		else return (0-(se<s_.se)+(se>s_.se));
	}
};
pair!(X,Y) make_pair(X,Y)(in X x_,in Y y_)
{
	pair!(X,Y) pp;
	pp.fi=x_;
	pp.se=y_;
	return pp;
}
nothrow void inf(in char* name) {freopen(name,"r",core.stdc.stdio.stdin);}
nothrow void ouf(in char* name) {freopen(name,"w",core.stdc.stdio.stdout);}
@property auto arread(T)(){return readln.split.map!(to!(T)).array;}
//split strip isAlpha isNumber isWhite isLower isUpper toLower toUpper mixin
//cumulativeFold schwartzSort multiSort partialSort heapify join filter countUntil
//---------------------------------------------------------------program beginning-----------------------------------------------------------------

void main()
{
	int n,m;
	loop:while(read(&n,&m))
	{
		auto g=new int[][m+1];
		foreach(i;1..n+1)
		{
			int k;
			input(&k);
			foreach(j;0..k)
			{
				int f;
				input(&f);
				g[f]~=i;
			}
		}
		int[int[]] q;
		foreach(i;g[1..$])
		{
			q[i.idup]++;
		}
		auto fact=(1L~iota(1L,5L*(10^^5)+1).array).cumulativeFold!"(a*b)%1000000007"(1L).array;
		long ans=1;
		foreach(i;q.byValue)
		{
			ans=(ans*fact[i])%mod;
		}
		/*long ans=1,t=1;
		sort(g[1..$]);
		debug foreach(i;g)writeln(i);
		foreach(i;2..m+1)
		{
			if(g[i]==g[i-1])
			{
				ans=(ans*(++t))%mod;
			}
			else t=1;
		}*/
		writeln(ans);
	}
}

module main;
import std.bigint,std.container,std.array,std.algorithm,std.conv,
	std.functional,std.math,std.numeric,std.string,std.range,std.complex,
	std.typecons,std.regex,std.random,std.uni,std.traits,std.variant,
	std.stdio,std.bitmanip;
import core.stdc.stdio : freopen;
alias BitArray bitset;
alias RedBlackTree Rbt;
alias redBlackTree rbt;
alias BigInt big;
alias pair!(int,int) pii;
alias pair!(long,long) pll;
alias BoyerMooreFinder strfind;
alias make_pair mp;
alias binary_search bins;
alias orient_square orsq;
immutable int mod=1000000007;
pure nothrow
{
	T lcm (T)(auto ref T a,auto ref T b)
	{
		return a/gcd(a,b)*b;
	}
	X binpow(X,Y)(X base,Y exp)
		if(is(typeof(exp&1)))
	{
		if(exp<0)return X(0);
		X res=X(1);
		while(exp>0)
		{
			if(exp&1)res*=base;
			base*=base;
			exp>>=1;
		}
		return res;
	}
	auto binpow(X,Y,Z)(X base,Y exp,in Z mm)
		if(is(typeof(exp&1)))
	{
		if(mm==0) return binpow(base,exp);
		if(exp<0)return X(0);
		auto res=X(1)%mm;
		while(exp>0)
		{
			if(exp&1)res=(res*base)%mm;
			base*=base;
			base%=mm;
			exp>>=1;
		}
		return res;
	}
	@property X sqr(X)(in X a_) {return a_*a_;}
	@property X cub(X)(in X a_) {return a_*a_*a_;}
	size_t lowb(T,X)(in T a,auto ref X g)
		if(isRandomAccessRange!T && hasLength!T && is(typeof(g<a[0])==bool))
	{
		size_t l=0,r=a.length;
		while(r-l>1)
		{
			auto m=(l+r)>>1;
			if(!(a[m]<g))r=m;
			else l=m;
		}
		return (!(a[l]<g))?l:r;
	}
	size_t upb(T,X)(in T a,auto ref X g)
		if(isRandomAccessRange!T && hasLength!T && is(typeof(g<a[0])==bool))
	{
		size_t l=0,r=a.length;
		while(r-l>1)
		{
			auto m=(l+r)>>1;
			if(g<a[m])r=m;
			else l=m;
		}
		return (g<a[l])?l:r;
	}
	size_t binf(T,X)(in T a,auto ref X g)
		if(isRandomAccessRange!T && hasLength!T && is(typeof(g<a[0])==bool))
	{
		size_t l=0,r=a.length;
		while(r-l>1)
		{
			auto m=(l+r)>>1;
			if(!(a[m]<g))r=m;
			else l=m;
		}
		return (g==a[l])?l:a.length;
	}
	bool binary_search(T,X)(in T a,auto ref X g)
		if(isRandomAccessRange!T && hasLength!T && is(typeof(g<a[0])==bool))
	{
		return binf(a,g)!=a.length;
	}
	V foldr(R,V,T)(R range,T arg,V nach)
		if(isFunction!T && isInputRange!R && is(typeof(arg(nach,R.front))==V))
	{
		for(;!range.empty;range.popFront()) nach=arg(nach,range.front);
		return nach;
	}
	size_t countr(R,T)(R range,T fun)
		if(isFunction!T && isInputRange!R && is(typeof(fun(R.front))==bool))
	{
		size_t nach;
		for(;!range.empty;range.popFront()) nach+=fun(range.front);
		return nach;
	}
	T orient_square(T)(pair!(T,T)[] figure...)
	{
		auto n=figure.front,t=figure.front;
		figure.popFront();
		T ans=0;
		for(;!figure.empty;figure.popFront())
		{
			ans+=(figure.front.fi-t.fi)*(figure.front.se+t.se);
			t=figure.front;
		}
		return ans+(n.fi-t.fi)*(n.se+t.se);
	}
	real square(T)(pair!(T,T)[] figure...)
		if(is(typeof(figure.front*figure.front)==T))
	{
		return abs(orient_square(figure))/2.000000000000000;
	}
}
void putarr(X)(in X a,in char ch=' '){foreach(const ref i;a)write(i,ch);}
void putarr(X)(in X a,in size_t n,in size_t m)
{
	foreach(i;0..n)
	{
		foreach(j;0..m)write(a[i][j],' ');
		writeln;
	}
}
bool getarr(X)(X a,in size_t n)
{bool b=1; foreach(ref i;a[0..n])b=input(&i);return b;}
bool input(T...)(T ptrs) if (ptrs.length > 0)
{return readf(replicate(" %s", ptrs.length), ptrs)==ptrs.length;}
bool read(T...)(T ptrs) if (ptrs.length > 0)
{return readf(replicate(" %s", ptrs.length)~'\n', ptrs)==ptrs.length;}
struct pair(X,Y)
{
	X first;
	Y second;
	alias first fi;
	alias second se;
	this(X a_,Y b_){
		fi=a_;
		se=b_;
	}
	this(this){fi=fi;se=se;}
	this(A,B)(auto ref pair!(A,B) p) if(is(A:X) && is(B:Y))
	{
		fi=p.fi;
		se=p.se;
	}
	int opCmp(A,B)(in pair!(A,B) s_) const
		if(is(typeof(s_.fi<fi)==bool) && is(typeof(s_.se<se)==bool))
	{
		int cmp=0-(fi<s_.fi)+(fi>s_.fi);
		if(cmp!=0)return cmp;
		else return (0-(se<s_.se)+(se>s_.se));
	}
};
pair!(X,Y) make_pair(X,Y)(in X x_,in Y y_)
{
	pair!(X,Y) pp;
	pp.fi=x_;
	pp.se=y_;
	return pp;
}
nothrow void inf(in char* name) {freopen(name,"r",core.stdc.stdio.stdin);}
nothrow void ouf(in char* name) {freopen(name,"w",core.stdc.stdio.stdout);}
@property auto arread(T)(){return readln.split.map!(to!(T)).array;}
//split strip isAlpha isNumber isWhite isLower isUpper toLower toUpper mixin
//cumulativeFold schwartzSort multiSort partialSort heapify join filter countUntil
//---------------------------------------------------------------program beginning-----------------------------------------------------------------

void main()
{
	int n,m;
	loop:while(read(&n,&m))
	{
		auto g=new int[][m+1];
		foreach(i;0..n)
		{
			int k;
			input(&k);
			foreach(j;0..k)
			{
				int f;
				input(&f);
				g[f]~=i;
			}
		}
		int[int[]] q;
		foreach(i;g)
		{
			if(i.length)q[i.idup]++;
		}
		auto fact=1L~iota(1L,5L*(10^^5)+1).cumulativeFold!"(a*b)%1000000007"(1L).array;
		long ans=1;
		foreach(i;q.byValue)
		{
			ans=(ans*fact[i])%mod;
		}
		writeln(ans);
	}
}

module main;
import std.bigint,std.container,std.array,std.algorithm,std.conv,
	std.functional,std.math,std.numeric,std.string,std.range,std.complex,
	std.typecons,std.regex,std.random,std.uni,std.traits,std.variant,
	std.stdio,std.bitmanip;
import core.stdc.stdio : freopen;
alias BitArray bitset;
alias RedBlackTree Rbt;
alias redBlackTree rbt;
alias BigInt big;
alias pair!(int,int) pii;
alias pair!(long,long) pll;
alias BoyerMooreFinder strfind;
alias make_pair mp;
alias binary_search bins;
alias orient_square orsq;
immutable int mod=1000000007;
pure nothrow
{
	T lcm (T)(auto ref T a,auto ref T b)
	{
		return a/gcd(a,b)*b;
	}
	X binpow(X,Y)(X base,Y exp)
		if(is(typeof(exp&1)))
	{
		if(exp<0)return X(0);
		X res=X(1);
		while(exp>0)
		{
			if(exp&1)res*=base;
			base*=base;
			exp>>=1;
		}
		return res;
	}
	auto binpow(X,Y,Z)(X base,Y exp,in Z mm)
		if(is(typeof(exp&1)))
	{
		if(mm==0) return binpow(base,exp);
		if(exp<0)return X(0);
		auto res=X(1)%mm;
		while(exp>0)
		{
			if(exp&1)res=(res*base)%mm;
			base*=base;
			base%=mm;
			exp>>=1;
		}
		return res;
	}
	@property X sqr(X)(in X a_) {return a_*a_;}
	@property X cub(X)(in X a_) {return a_*a_*a_;}
	size_t lowb(T,X)(in T a,auto ref X g)
		if(isRandomAccessRange!T && hasLength!T && is(typeof(g<a[0])==bool))
	{
		size_t l=0,r=a.length;
		while(r-l>1)
		{
			auto m=(l+r)>>1;
			if(!(a[m]<g))r=m;
			else l=m;
		}
		return (!(a[l]<g))?l:r;
	}
	size_t upb(T,X)(in T a,auto ref X g)
		if(isRandomAccessRange!T && hasLength!T && is(typeof(g<a[0])==bool))
	{
		size_t l=0,r=a.length;
		while(r-l>1)
		{
			auto m=(l+r)>>1;
			if(g<a[m])r=m;
			else l=m;
		}
		return (g<a[l])?l:r;
	}
	size_t binf(T,X)(in T a,auto ref X g)
		if(isRandomAccessRange!T && hasLength!T && is(typeof(g<a[0])==bool))
	{
		size_t l=0,r=a.length;
		while(r-l>1)
		{
			auto m=(l+r)>>1;
			if(!(a[m]<g))r=m;
			else l=m;
		}
		return (g==a[l])?l:a.length;
	}
	bool binary_search(T,X)(in T a,auto ref X g)
		if(isRandomAccessRange!T && hasLength!T && is(typeof(g<a[0])==bool))
	{
		return binf(a,g)!=a.length;
	}
	V foldr(R,V,T)(R range,T arg,V nach)
		if(isFunction!T && isInputRange!R && is(typeof(arg(nach,R.front))==V))
	{
		for(;!range.empty;range.popFront()) nach=arg(nach,range.front);
		return nach;
	}
	size_t countr(R,T)(R range,T fun)
		if(isFunction!T && isInputRange!R && is(typeof(fun(R.front))==bool))
	{
		size_t nach;
		for(;!range.empty;range.popFront()) nach+=fun(range.front);
		return nach;
	}
	T orient_square(T)(pair!(T,T)[] figure...)
	{
		auto n=figure.front,t=figure.front;
		figure.popFront();
		T ans=0;
		for(;!figure.empty;figure.popFront())
		{
			ans+=(figure.front.fi-t.fi)*(figure.front.se+t.se);
			t=figure.front;
		}
		return ans+(n.fi-t.fi)*(n.se+t.se);
	}
	real square(T)(pair!(T,T)[] figure...)
		if(is(typeof(figure.front*figure.front)==T))
	{
		return abs(orient_square(figure))/2.000000000000000;
	}
}
void putarr(X)(in X a,in char ch=' '){foreach(const ref i;a)write(i,ch);}
void putarr(X)(in X a,in size_t n,in size_t m)
{
	foreach(i;0..n)
	{
		foreach(j;0..m)write(a[i][j],' ');
		writeln;
	}
}
bool getarr(X)(X a,in size_t n)
{bool b=1; foreach(ref i;a[0..n])b=input(&i);return b;}
bool input(T...)(T ptrs) if (ptrs.length > 0)
{return readf(replicate(" %s", ptrs.length), ptrs)==ptrs.length;}
bool read(T...)(T ptrs) if (ptrs.length > 0)
{return readf(replicate(" %s", ptrs.length)~'\n', ptrs)==ptrs.length;}
struct pair(X,Y)
{
	X first;
	Y second;
	alias first fi;
	alias second se;
	this(X a_,Y b_){
		fi=a_;
		se=b_;
	}
	this(this){fi=fi;se=se;}
	this(A,B)(auto ref pair!(A,B) p) if(is(A:X) && is(B:Y))
	{
		fi=p.fi;
		se=p.se;
	}
	int opCmp(A,B)(in pair!(A,B) s_) const
		if(is(typeof(s_.fi<fi)==bool) && is(typeof(s_.se<se)==bool))
	{
		int cmp=0-(fi<s_.fi)+(fi>s_.fi);
		if(cmp!=0)return cmp;
		else return (0-(se<s_.se)+(se>s_.se));
	}
};
pair!(X,Y) make_pair(X,Y)(in X x_,in Y y_)
{
	pair!(X,Y) pp;
	pp.fi=x_;
	pp.se=y_;
	return pp;
}
nothrow void inf(in char* name) {freopen(name,"r",core.stdc.stdio.stdin);}
nothrow void ouf(in char* name) {freopen(name,"w",core.stdc.stdio.stdout);}
@property auto arread(T)(){return readln.split.map!(to!(T)).array;}
//split strip isAlpha isNumber isWhite isLower isUpper toLower toUpper mixin
//cumulativeFold schwartzSort multiSort partialSort heapify join filter countUntil
//---------------------------------------------------------------program beginning-----------------------------------------------------------------

void main()
{
	int n,m;
	loop:while(read(&n,&m))
	{
		auto g=new int[][m+1];
		foreach(i;0..n)
		{
			int k;
			input(&k);
			foreach(j;0..k)
			{
				int f;
				input(&f);
				g[f]~=i;
			}
		}
		int[int[]] q;
		foreach(i;g)
		{
			if(i.length)q[i.idup]++;
		}
		auto fact=(1L~iota(1L,5L*(10^^5)+1).array).cumulativeFold!"(a*b)%1000000007"(1L).array;
		long ans=1;
		foreach(i;q.byValue)
		{
			ans=(ans*fact[i])%mod;
		}
		writeln(ans);
	}
}

module main;
import std.bigint,std.container,std.array,std.algorithm,std.conv,
	std.functional,std.math,std.numeric,std.string,std.range,std.complex,
	std.typecons,std.regex,std.random,std.uni,std.traits,std.variant,
	std.stdio,std.bitmanip;
import core.stdc.stdio : freopen;
alias BitArray bitset;
alias RedBlackTree Rbt;
alias redBlackTree rbt;
alias BigInt big;
alias pair!(int,int) pii;
alias pair!(long,long) pll;
alias BoyerMooreFinder strfind;
alias make_pair mp;
alias binary_search bins;
alias orient_square orsq;
immutable int mod=1000000007;
pure nothrow
{
	T lcm (T)(auto ref T a,auto ref T b)
	{
		return a/gcd(a,b)*b;
	}
	X binpow(X,Y)(X base,Y exp)
		if(is(typeof(exp&1)))
	{
		if(exp<0)return X(0);
		X res=X(1);
		while(exp>0)
		{
			if(exp&1)res*=base;
			base*=base;
			exp>>=1;
		}
		return res;
	}
	auto binpow(X,Y,Z)(X base,Y exp,in Z mm)
		if(is(typeof(exp&1)))
	{
		if(mm==0) return binpow(base,exp);
		if(exp<0)return X(0);
		auto res=X(1)%mm;
		while(exp>0)
		{
			if(exp&1)res=(res*base)%mm;
			base*=base;
			base%=mm;
			exp>>=1;
		}
		return res;
	}
	@property X sqr(X)(in X a_) {return a_*a_;}
	@property X cub(X)(in X a_) {return a_*a_*a_;}
	size_t lowb(T,X)(in T a,auto ref X g)
		if(isRandomAccessRange!T && hasLength!T && is(typeof(g<a[0])==bool))
	{
		size_t l=0,r=a.length;
		while(r-l>1)
		{
			auto m=(l+r)>>1;
			if(!(a[m]<g))r=m;
			else l=m;
		}
		return (!(a[l]<g))?l:r;
	}
	size_t upb(T,X)(in T a,auto ref X g)
		if(isRandomAccessRange!T && hasLength!T && is(typeof(g<a[0])==bool))
	{
		size_t l=0,r=a.length;
		while(r-l>1)
		{
			auto m=(l+r)>>1;
			if(g<a[m])r=m;
			else l=m;
		}
		return (g<a[l])?l:r;
	}
	size_t binf(T,X)(in T a,auto ref X g)
		if(isRandomAccessRange!T && hasLength!T && is(typeof(g<a[0])==bool))
	{
		size_t l=0,r=a.length;
		while(r-l>1)
		{
			auto m=(l+r)>>1;
			if(!(a[m]<g))r=m;
			else l=m;
		}
		return (g==a[l])?l:a.length;
	}
	bool binary_search(T,X)(in T a,auto ref X g)
		if(isRandomAccessRange!T && hasLength!T && is(typeof(g<a[0])==bool))
	{
		return binf(a,g)!=a.length;
	}
	V foldr(R,V,T)(R range,T arg,V nach)
		if(isFunction!T && isInputRange!R && is(typeof(arg(nach,R.front))==V))
	{
		for(;!range.empty;range.popFront()) nach=arg(nach,range.front);
		return nach;
	}
	size_t countr(R,T)(R range,T fun)
		if(isFunction!T && isInputRange!R && is(typeof(fun(R.front))==bool))
	{
		size_t nach;
		for(;!range.empty;range.popFront()) nach+=fun(range.front);
		return nach;
	}
	T orient_square(T)(pair!(T,T)[] figure...)
	{
		auto n=figure.front,t=figure.front;
		figure.popFront();
		T ans=0;
		for(;!figure.empty;figure.popFront())
		{
			ans+=(figure.front.fi-t.fi)*(figure.front.se+t.se);
			t=figure.front;
		}
		return ans+(n.fi-t.fi)*(n.se+t.se);
	}
	real square(T)(pair!(T,T)[] figure...)
		if(is(typeof(figure.front*figure.front)==T))
	{
		return abs(orient_square(figure))/2.000000000000000;
	}
}
void putarr(X)(in X a,in char ch=' '){foreach(const ref i;a)write(i,ch);}
void putarr(X)(in X a,in size_t n,in size_t m)
{
	foreach(i;0..n)
	{
		foreach(j;0..m)write(a[i][j],' ');
		writeln;
	}
}
bool getarr(X)(X a,in size_t n)
{bool b=1; foreach(ref i;a[0..n])b=input(&i);return b;}
bool input(T...)(T ptrs) if (ptrs.length > 0)
{return readf(replicate(" %s", ptrs.length), ptrs)==ptrs.length;}
bool read(T...)(T ptrs) if (ptrs.length > 0)
{return readf(replicate(" %s", ptrs.length)~'\n', ptrs)==ptrs.length;}
struct pair(X,Y)
{
	X first;
	Y second;
	alias first fi;
	alias second se;
	this(X a_,Y b_){
		fi=a_;
		se=b_;
	}
	this(this){fi=fi;se=se;}
	this(A,B)(auto ref pair!(A,B) p) if(is(A:X) && is(B:Y))
	{
		fi=p.fi;
		se=p.se;
	}
	int opCmp(A,B)(in pair!(A,B) s_) const
		if(is(typeof(s_.fi<fi)==bool) && is(typeof(s_.se<se)==bool))
	{
		int cmp=0-(fi<s_.fi)+(fi>s_.fi);
		if(cmp!=0)return cmp;
		else return (0-(se<s_.se)+(se>s_.se));
	}
};
pair!(X,Y) make_pair(X,Y)(in X x_,in Y y_)
{
	pair!(X,Y) pp;
	pp.fi=x_;
	pp.se=y_;
	return pp;
}
nothrow void inf(in char* name) {freopen(name,"r",core.stdc.stdio.stdin);}
nothrow void ouf(in char* name) {freopen(name,"w",core.stdc.stdio.stdout);}
@property auto arread(T)(){return readln.split.map!(to!(T)).array;}
//split strip isAlpha isNumber isWhite isLower isUpper toLower toUpper mixin
//cumulativeFold schwartzSort multiSort partialSort heapify join filter countUntil
//---------------------------------------------------------------program beginning-----------------------------------------------------------------

void main()
{
	int n,m;
	loop:while(read(&n,&m))
	{
		auto g=new int[][m+1];
		foreach(i;0..n)
		{
			int k;
			input(&k);
			foreach(j;0..k)
			{
				int f;
				input(&f);
				g[f]~=i;
			}
		}
		int[int[]] q;
		foreach(i;g)
		{
			if(i.length)q[i.idup]++;
		}
		auto fact=1~iota(1,5*(10^^5)+1).cumulativeFold!"(a*b)%1000000007"(1).array;
		long ans=1;
		foreach(i;q.byValue)
		{
			ans=(ans*fact[i])%mod;
		}
		writeln(ans);
	}
}

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

void main()
{
    int n, m;
    readf("%s %s", &n, &m);
    readln;

    auto idx = new int[] (m+1);
    int nxtid = 1;
    foreach (_; 0 .. n) {
        auto nrs = readln.chomp.split.map!(to!int).dropOne.array;

        int[int] cnt;

        foreach (e; nrs) { cnt[e] += 1; }

        int[][int] groups;
        foreach (p; cnt.byKeyValue) {
            groups[p.value] ~= p.key;
        }

        debug { groups.writeln; }

        foreach (arr; groups.values) {
            arr.schwartzSort!(x => idx[x]);

            debug { arr.writeln; }

            foreach (p, n; lockstep(arr, arr.dropOne)) {
                bool inc = idx[p] != idx[n];

                idx[p] = nxtid;

                if (inc) { nxtid += 1; }
            }

            idx[arr.back] = nxtid;

            ++nxtid;
        }
    }

    debug { idx.writeln; }

    auto grouped = idx.dropOne.sort.group.map!(t => t[1]);

    debug { grouped.writeln; }

    immutable int MD = 10 ^^ 9 + 23;

    auto fac = new int[] (m+1);
    fac[0] = 1;
    foreach (i; 1 .. m+1) { fac[i] = fac[i-1].to!long * i % MD; }

    auto ans = grouped.map!(x => fac[x])
        .fold!((x, y) => (x.to!long * y % MD).to!int)(1);

    ans.writeln;
}

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

void main()
{
    int n, m;
    readf("%s %s", &n, &m);
    readln;

    auto idx = new int[] (m+1);
    int nxtid = 1;
    foreach (_; 0 .. n) {
        auto nrs = readln.chomp.split.map!(to!int).dropOne.array;

        int[int] cnt;

        foreach (e; nrs) { cnt[e] += 1; }

        int[][int] groups;
        foreach (p; cnt.byKeyValue) {
            groups[p.value] ~= p.key;
        }

        debug { groups.writeln; }

        foreach (arr; groups.values) {
            arr.schwartzSort!(x => idx[x]);

            debug { arr.writeln; }

            foreach (p, n; lockstep(arr, arr.dropOne)) {
                bool inc = idx[p] != idx[n];

                idx[p] = nxtid;

                if (inc) { nxtid += 1; }
            }

            idx[arr.back] = nxtid;
        }

        ++nxtid;
    }

    debug { idx.writeln; }

    auto grouped = idx.dropOne.sort.group.map!(t => t[1]);

    debug { grouped.writeln; }

    immutable int MD = 10 ^^ 9 + 23;

    auto fac = new int[] (m+1);
    fac[0] = 1;
    foreach (i; 1 .. m+1) { fac[i] = fac[i-1].to!long * i % MD; }

    auto ans = grouped.map!(x => fac[x])
        .fold!((x, y) => (x.to!long * y % MD).to!int)(1);

    ans.writeln;
}


module main;
__gshared:
import core.bitop, std.algorithm, std.bigint, std.bitmanip, std.complex,
	std.container, std.conv, std.datetime, std.functional, std.math, std.meta;
import std.numeric : Fft, fft, gcd, inverseFft;
import std.parallelism, std.random, std.range, std.regex, std.stdio, std.string,
	std.traits, std.typecons, std.uni, std.variant;

alias pair(X, Y) = Tuple!(X, "fi", Y, "se");
alias mp = make_pair;
alias pii = pair!(int, int);
alias pll = pair!(long, long);
alias gcd = std.numeric.gcd;
alias lint = long;
alias rbt = RedBlackTree;
///modulo
enum mod = 10 ^^ 9 + 7, mod2 = mod + 2;
public
{
	pure nothrow
	{
		///lcm
		T lcm(T)(auto ref T a, auto ref T b)
		{
			return a / gcd(a, b) * b;
		}
		///make_pair
		pair!(X, Y) make_pair(X, Y)(in X x_, in Y y_)
		{
			return tuple!(X, "fi", Y, "se")(x_, y_);
		}
		///BigInt greatest common divizor
		BigInt gcd(BigInt a, BigInt b)
		{
			while (b)
			{
				a %= b;
				swap(a, b);
			}
			return a;
		}
		///square
		@property X sqr(X)(in X a_)
		{
			return a_ * a_;
		}
		///cube
		@property X cub(X)(in X a_)
		{
			return a_ * a_ * a_;
		}
		///integer size
		int sz(T)(T a) if (hasLength!T)
		{
			return cast(int) a.length;
		}
		///posicion lower bound
		size_t lowb(T, X)(T a, auto ref X g)
				if (isRandomAccessRange!T && hasLength!T && is(typeof(g < a[0]) == bool))
		{
			size_t l = 0, r = a.length;
			while (r - l > 1)
			{
				auto m = (l + r) >> 1;
				if (!(a[m] < g))
					r = m;
				else
					l = m;
			}
			return (!(a[l] < g)) ? l : r;
		}
		///posicion upper bound
		size_t upb(T, X)(T a, auto ref X g)
				if (isRandomAccessRange!T && hasLength!T && is(typeof(g < a[0]) == bool))
		{
			size_t l = 0, r = a.length;
			while (r - l > 1)
			{
				auto m = (l + r) >> 1;
				if (g < a[m])
					r = m;
				else
					l = m;
			}
			return (g < a[l]) ? l : r;
		}
		///posicion binary search
		size_t binf(T, X)(T a, auto ref X g)
				if (isRandomAccessRange!T && hasLength!T && is(typeof(g < a[0]) == bool))
		{
			auto pos = lowb(a, g);
			return (g == a[pos]) ? pos : a.length;
		}
		///binary search
		bool binary_search(T, X)(T a, auto ref X g)
				if (isRandomAccessRange!T && hasLength!T && is(typeof(g < a[0]) == bool))
		{
			return binf(a, g) != a.length;
		}
	}
	///write an array
	void putarr(X)(in X a, in char ch = ' ') if (isInputRange!X)
	{
		writefln("%(%s" ~ ch ~ "%)", a);
	}
	///write a matrix
	void putarr(X)(in X a)
			if (isInputRange!X && isInputRange!(ElementType!X) && !isSomeString!(ElementType!X))
	{
		writefln("%(%(%s %)\n%)", a);
	}
	///get an array
	bool getarr(X)(X a, in size_t n)
	{
		bool b = 1;
		foreach (ref i; a[0 .. n])
			b = input(&i);
		return b;
	}
	///read without format
	bool input(T...)(ref T ptrs) if (ptrs.length > 0)
	{
		size_t s = 0;
		foreach (ref e; ptrs)
		{
			if (isSomeChar!(Unqual!(typeof(e))))
				s += readf(" %c", &e);
			else
				s += readf(" %s", &e);
		}
		return s == ptrs.length;
	}
	///readln without format
	bool read(T...)(ref T ptrs) if (ptrs.length > 0)
	{
		size_t s = 0;
		foreach (ref e; ptrs)
		{
			if (isSomeChar!(Unqual!(typeof(e))))
				s += readf(" %c", &e);
			else
				s += readf(" %s", &e);
		}
		readln;
		return s == ptrs.length;
	}
	///opening file
	nothrow auto inf(in char* name)
	{
		return freopen(name, "r", core.stdc.stdio.stdin);
	}
	///closing file
	nothrow auto ouf(in char* name)
	{
		return freopen(name, "w", core.stdc.stdio.stdout);
	}
	///parsing array from line
	@property auto arread(T)()
	{
		return readln.splitter.map!(to!(T)).array;
	}
	///outbuffer
	void enter(T...)(T args)
	{
		writeln(args);
		stdout.flush;
	}
}
//foreach_reverse isAlpha isNumber isWhite isLower isUpper toLower toUpper mixin
//cumulativeFold return static heapify join filter foreach
//------------------------------------------program beginning--------------------------

void main()
{
	version (home)
	{
		freopen("input.txt", "r", core.stdc.stdio.stdin);
		//freopen("output.txt", "w", core.stdc.stdio.stdout);
		/*StopWatch sw;
		sw.start;
		scope (exit)
		{
			sw.stop;
			stderr.writefln("\nTime: %d ms", sw.peek.msecs);
		}*/
	}
	int n;
	loop: while (read(n))
	{
		pii[] a;
		foreach (_; 0 .. n)
		{
			int l, r;
			read(l, r);
			a ~= mp(l, 0);
			a ~= mp(r, 1);
		}
		sort(a);
		int c;
		foreach (x; a)
		{
			if (x.se > 0)
				c--;
			else
				c++;
			if (c > 2)
			{
				writeln("NO");
				continue loop;
			}
		}
		writeln("YES");
	}
}

// Codeforces My Practice
// author: Leonardone @ NEETSDKASU
import std.stdio     : readln, writeln;
import std.string    : chomp;
import std.array     : split, appender;
import std.conv      : to;
import std.typecons  : Tuple;
import std.algorithm : sort;

auto gets() { return readln.chomp; }
auto getNum(T)() { return gets.to!T; }
auto getVals(T)() { return gets.split.to!(T[]); }

void main() {
    alias Tp = Tuple!(int, "s", int, "e");
    auto n = getNum!int;
    auto ap = appender!(Tp[])();
    auto endsAp = appender!(Tp[])();
    foreach (_; 0..n) {
        auto se = getVals!int;
        ap.put(Tp(se[0], se[1]));
    }
    auto prgs = ap.data[];
    prgs.sort!"a.s < b.s";
    auto tv1 = Tp(-1,-1), tv2 = Tp(-1,-1);
    foreach (tp; prgs) {
        if (tv1.e < tp.s) {
            tv1 = tp;
            continue;
        }
        if (tv2.e < tp.s) {
            tv2 = tp;
            continue;
        }
        writeln("NO");
        return;
    }
    writeln("YES");
}

// Try Codeforces
// author: Leonardone @ NEETSDKASU
import std.stdio     : readln, writeln;
import std.string    : chomp;
import std.array     : split, appender;
import std.conv      : to;
import std.typecons  : Tuple;
import std.algorithm : sort;

auto gets() { return readln.chomp; }
auto getNum(T)() { return gets.to!T; }
auto getVals(T)() { return gets.split.to!(T[]); }

void main() {
    alias Tp = Tuple!(int, "s", int, "e", int, "p");
    auto n = getNum!int;
    auto ap = appender!(Tp[])();
    auto endsAp = appender!(Tp[])();
    foreach (i; 0..n) {
        auto se = getVals!int;
        ap.put(Tp(se[0], se[1], i));
    }
    auto prgs = ap.data[];
    prgs.sort!( (a, b) => a.s!=b.s ? a.s<b.s : (a.e!=b.e ? a.e<b.e : a.p<b.p) );
    auto tv1 = Tp(-1,-1,-1), tv2 = tv1;
    foreach (i,tp; prgs) {
        if (tv1.e < tp.s && tv2.e < tp.s) {
            tv1 = tp;
            continue;
        }
        if (tv1.e < tp.s && tv2.e == tp.s) {
            tv1 = tp;
            continue;
        }
        if (tv2.e < tp.s && tv1.e == tp.s) {
            tv2 = tp;
            continue;
        }
        writeln("NO");
        return;
    }
    writeln("YES");
}

// Try Codeforces
// author: Leonardone @ NEETSDKASU
import std.stdio     : readln, writeln;
import std.string    : chomp;
import std.array     : split, appender;
import std.conv      : to;
import std.typecons  : Tuple;
import std.algorithm : sort;

auto gets() { return readln.chomp; }
auto getNum(T)() { return gets.to!T; }
auto getVals(T)() { return gets.split.to!(T[]); }

void main() {
    alias Tp = Tuple!(long, "s", long, "e", long, "p");
    auto n = getNum!int;
    auto ap = appender!(Tp[])();
    auto endsAp = appender!(Tp[])();
    foreach (i; 0..n) {
        auto se = getVals!long;
        ap.put(Tp(se[0], se[1], i));
    }
    auto prgs = ap.data[];
    prgs.sort!( (a, b) => a.s!=b.s ? a.s<b.s : (a.e!=b.e ? a.e<b.e : a.p<b.p) );
    auto tv1 = Tp(-1,-1,-1), tv2 = tv1;
    foreach (tp; prgs) {
        if (tv1.e < tp.s && tv2.e < tp.s) {
            tv1 = tp;
            continue;
        }
        if (tv1.e < tp.s && tv2.e == tp.s) {
            tv1 = tp;
            continue;
        }
        if (tv2.e < tp.s && tv1.e == tp.s) {
            tv2 = tp;
            continue;
        }
        writeln("NO");
        return;
    }
    writeln("YES");
}

// Try Codeforces
// author: Leonardone @ NEETSDKASU
import std.stdio     : readln, writeln;
import std.string    : chomp;
import std.array     : split, appender;
import std.conv      : to;
import std.typecons  : Tuple;
import std.algorithm : sort;

auto gets() { return readln.chomp; }
auto getNum(T)() { return gets.to!T; }
auto getVals(T)() { return gets.split.to!(T[]); }

void main() {
    alias Tp = Tuple!(int, "s", int, "e");
    auto n = getNum!int;
    auto ap = appender!(Tp[])();
    auto endsAp = appender!(Tp[])();
    foreach (_; 0..n) {
        auto se = getVals!int;
        ap.put(Tp(se[0], se[1]));
    }
    auto prgs = ap.data[];
    prgs.sort!"a.s < b.s";
    auto tv1 = Tp(-1,-1), tv2 = Tp(-1,-1);
    foreach (tp; prgs) {
        if (tv1.e < tp.s && tv2.e < tp.s) {
            tv1 = tp;
            continue;
        }
        if (tv1.e <= tp.s && tv2.e == tp.s) {
            tv1 = tp;
            continue;
        }
        if (tv2.e <= tp.s && tv1.e == tp.s) {
            tv2 = tp;
            continue;
        }
        writeln("NO");
        return;
    }
    writeln("YES");
}

// Try Codeforces
// author: Leonardone @ NEETSDKASU
import std.stdio     : readln, writeln;
import std.string    : chomp;
import std.array     : split, appender;
import std.conv      : to;
import std.typecons  : Tuple;
import std.algorithm : sort;

auto gets() { return readln.chomp; }
auto getNum(T)() { return gets.to!T; }
auto getVals(T)() { return gets.split.to!(T[]); }

void main() {
    alias Tp = Tuple!(int, "s", int, "e");
    auto n = getNum!int;
    auto ap = appender!(Tp[])();
    auto endsAp = appender!(Tp[])();
    foreach (_; 0..n) {
        auto se = getVals!int;
        ap.put(Tp(se[0], se[1]));
    }
    auto prgs = ap.data[];
    prgs.sort!"a.s < b.s";
    auto tv1 = Tp(-1,-1), tv2 = Tp(-1,-1);
    foreach (tp; prgs) {
        if (tv1.e < tp.s && tv2.e < tp.s) {
            tv1 = tp;
            continue;
        }
        if (tv1.e < tp.s && tv2.e == tp.s) {
            tv1 = tp;
            continue;
        }
        if (tv2.e < tp.s && tv1.e == tp.s) {
            tv2 = tp;
            continue;
        }
        writeln("NO");
        return;
    }
    writeln("YES");
}

// Try Codeforces
// author: Leonardone @ NEETSDKASU
import std.stdio     : readln, writeln;
import std.string    : chomp;
import std.array     : split, appender;
import std.conv      : to;
import std.typecons  : Tuple;
import std.algorithm : sort;

auto gets() { return readln.chomp; }
auto getNum(T)() { return gets.to!T; }
auto getVals(T)() { return gets.split.to!(T[]); }

void main() {
    alias Tp = Tuple!(int, "s", int, "e", int, "p");
    auto n = getNum!int;
    auto ap = appender!(Tp[])();
    auto endsAp = appender!(Tp[])();
    foreach (i; 0..n) {
        auto se = getVals!int;
        ap.put(Tp(se[0], se[1], i));
    }
    auto prgs = ap.data[];
    prgs.sort!( (a, b) => a.s!=b.s ? a.s<b.s : (a.e!=b.e ? a.e<b.e : a.p<b.p) );
    auto tv1 = Tp(-1,-1,-1), tv2 = tv1;
    foreach (i,tp; prgs) {
        if (tv1.e < tp.s && tv2.e < tp.s) {
            tv1 = tp;
            continue;
        }
        if (tv1.s < 0 && tv2.e == tp.s) {
            tv1 = tp;
            continue;
        }
        if (tv2.s < 0 && tv1.e == tp.s) {
            tv2 = tp;
            continue;
        }
        writeln("NO");
        return;
    }
    writeln("YES");
}

// Try Codeforces
// author: Leonardone @ NEETSDKASU
import std.stdio     : readln, writeln;
import std.string    : chomp;
import std.array     : split, appender;
import std.conv      : to;
import std.typecons  : Tuple;
import std.algorithm : sort;

auto gets() { return readln.chomp; }
auto getNum(T)() { return gets.to!T; }
auto getVals(T)() { return gets.split.to!(T[]); }

void main() {
    alias Tp = Tuple!(int, "t", int, "p");
    auto n = getNum!int;
    auto startsAp = appender!(Tp[])();
    auto endsAp = appender!(Tp[])();
    foreach (i; 0..n) {
        auto se = getVals!int;
        startsAp.put(Tp(se[0], i));
        endsAp.put(Tp(se[1], i));
    }
    auto starts = startsAp.data[];
    auto ends = endsAp.data[];
    starts.sort!"a.t < b.t";
    ends.sort!"a.t < b.t";
    auto tv1 = -1, tv2 = -1;
    auto useTv1 = false, useTv2 = false;
    while (starts.length > 0) {
        if (starts[0].t <= ends[0].t) {
            if (tv1 < 0) {
                tv1 = starts[0].p;
                useTv1 = true;
            } else if (tv2 < 0) {
                tv2 = starts[0].p;
                useTv2 = true;
            } else {
                writeln("NO");
                return;
            }
            starts = starts[1..$];
        } else if (starts[0].t > ends[0].t) {
            if (tv1 == ends[0].p) {
                tv1 = -1;
            } else if (tv2 == ends[0].p) {
                tv2 = -1;
            } else {
                writeln("NO");
                return;
            }
            ends = ends[1..$];
        }
    }
    writeln(useTv1 && useTv2 ? "YES" : "NO");
}

// Try Codeforces
// author: Leonardone @ NEETSDKASU
import std.stdio     : readln, writeln;
import std.string    : chomp;
import std.array     : split, appender;
import std.conv      : to;
import std.typecons  : Tuple;
import std.algorithm : sort;

auto gets() { return readln.chomp; }
auto getNum(T)() { return gets.to!T; }
auto getVals(T)() { return gets.split.to!(T[]); }

void main() {
    alias Tp = Tuple!(int, "t", int, "p");
    auto n = getNum!int;
    auto startsAp = appender!(Tp[])();
    auto endsAp = appender!(Tp[])();
    foreach (i; 0..n) {
        auto se = getVals!int;
        startsAp.put(Tp(se[0], i));
        endsAp.put(Tp(se[1], i));
    }
    auto starts = startsAp.data[];
    auto ends = endsAp.data[];
    starts.sort!( (a, b) => a.t == b.t ? a.p < b.p : a.t < b.t );
    ends.sort!( (a, b) => a.t == b.t ? a.p < b.p : a.t < b.t );
    auto tv1 = -1, tv2 = -1;
    while (starts.length > 0) {
        if (starts[0].t <= ends[0].t) {
            if (tv1 < 0) {
                tv1 = starts[0].p;
            } else if (tv2 < 0) {
                tv2 = starts[0].p;
            } else {
                writeln("NO");
                return;
            }
            starts = starts[1..$];
        } else {
            if (tv1 == ends[0].p) {
                tv1 = -1;
            } else if (tv2 == ends[0].p) {
                tv2 = -1;
            } else {
                writeln("NO");
                return;
            }
            ends = ends[1..$];
        }
    }
    writeln("YES");
}

// Try Codeforces
// author: Leonardone @ NEETSDKASU
import std.stdio     : readln, writeln;
import std.string    : chomp;
import std.array     : split, appender;
import std.conv      : to;
import std.typecons  : Tuple;
import std.algorithm : sort;

auto gets() { return readln.chomp; }
auto getNum(T)() { return gets.to!T; }
auto getVals(T)() { return gets.split.to!(T[]); }

void main() {
    alias Tp = Tuple!(int, "t", int, "p");
    auto n = getNum!int;
    auto startsAp = appender!(Tp[])();
    auto endsAp = appender!(Tp[])();
    foreach (i; 0..n) {
        auto se = getVals!int;
        startsAp.put(Tp(se[0], i));
        endsAp.put(Tp(se[1], i));
    }
    auto starts = startsAp.data[];
    auto ends = endsAp.data[];
    starts.sort!"a.t < b.t";
    ends.sort!"a.t < b.t";
    auto tv1 = -1, tv2 = -1;
    while (starts.length > 0) {
        if (starts[0].t <= ends[0].t) {
            if (tv1 < 0) {
                tv1 = starts[0].p;
            } else if (tv2 < 0) {
                tv2 = starts[0].p;
            } else {
                writeln("NO");
                return;
            }
            starts = starts[1..$];
        } else if (starts[0].t > ends[0].t) {
            if (tv1 == ends[0].p) {
                tv1 = -1;
            } else if (tv2 == ends[0].p) {
                tv2 = -1;
            } else {
                writeln("NO");
                return;
            }
            ends = ends[1..$];
        }
    }
    writeln("YES");
}

// Try Codeforces
// author: Leonardone @ NEETSDKASU
import std.stdio     : readln, writeln;
import std.string    : chomp;
import std.array     : split, appender;
import std.conv      : to;
import std.typecons  : Tuple;
import std.algorithm : sort;

auto gets() { return readln.chomp; }
auto getNum(T)() { return gets.to!T; }
auto getVals(T)() { return gets.split.to!(T[]); }

void main() {
    alias Tp = Tuple!(int, "s", int, "e", int, "p");
    auto n = getNum!int;
    auto ap = appender!(Tp[])();
    auto endsAp = appender!(Tp[])();
    foreach (i; 0..n) {
        auto se = getVals!int;
        ap.put(Tp(se[0], se[1], i));
    }
    auto prgs = ap.data[];
    prgs.sort!( (a, b) => a.s!=b.s ? a.s<b.s : (a.e!=b.e ? a.e<b.e : a.p<b.p) );
    auto tv1 = Tp(-1,-1,-1), tv2 = tv1;
    foreach (i,tp; prgs) {
        if (tv1.e < tp.s && tv2.e < tp.s) {
            tv1 = tp;
            continue;
        }
        if (tv1.e < tp.s && tv2.e == tp.s) {
            tv1 = tp;
            continue;
        }
        if (tv2.e < tp.s && tv1.e == tp.s) {
            tv2 = tp;
            continue;
        }
        writeln("NO");
        return;
    }
    writeln(tv2.e < 0 ? "NO" : "YES");
}


import core.bitop, std.bitmanip;
import core.checkedint;
import std.algorithm, std.functional, std.meta;
import std.array, std.container;
import std.bigint;
import std.conv;
import std.math, std.numeric;
import std.range, std.range.interfaces;
import std.stdio, std.string;
import std.ascii, std.typecons;

void main()
{
    int t;
    readf("%s", &t);
    readln;

    while (t--) {
        int n;
        readf("%s", &n);
        readln;

        auto s = readln.chomp;
        s ~= '2';
        int le = 0, r = 0;
        int ans = 0;
        while (le < n) {
            r = max(r, le);

            bool found = false;
            while (r+1 < n && s[r] != s[r+1]) { ++r; }
            found = r+1 < n;
            ++r;

            if (!found) {
                while (le < n && (le == n-1 || s[le] == s[le+1])) { ++le; }
                ++le;
            }

            while (le < n && (le == n-1 || s[le] == s[le+1])) { ++le; }
            ++le;

            ans += 1;
        }

        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)); }

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 long[](t);
	foreach (ti; 0..t)
	{
		auto n = RD!int;
		auto s = RD!string;

		char last = s[0];
		int[] a;
		int cnt;
		foreach (i; 0..n)
		{
			if (s[i] == last)
				++cnt;
			else
			{
				a ~= cnt;
				cnt = 1;
				last = s[i];
			}
		}
		a ~= cnt;
		debug writeln(a);

		long c;
		foreach (e; a)
		{
			++c;
			auto x = min(e-1, c);
			c -= x;
			ans[ti] += x;
		}
		ans[ti] += (c+1) / 2;
	}

	foreach (ti; 0..t)
	{
		writeln(ans[ti]);
	}
	stdout.flush;
	debug readln;
}


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() {
    auto N = readln.chomp.to!int;
    auto G = new int[][](N);
    foreach (_; 0..N-1) {
        auto s = readln.split.map!(to!int);
        G[s[0]-1] ~= s[1]-1;
        G[s[1]-1] ~= s[0]-1;
    }
    auto A = readln.split.map!(x => x.to!int-1).array;

    auto D = new int[](N);
    auto E = new int[][](N);
    auto P = new int[](N);
    auto order = new int[](N);

    void dfs(int n, int p, int d) {
        P[n] = p;
        D[n] = d;
        E[d] ~= n;
        foreach (m; G[n]) if (m != p) dfs(m, n, d+1);
    }
    dfs(0, -1, 0);

    foreach (i; 0..N-1) {
        if (D[A[i]] > D[A[i+1]]) {
            writeln("No");
            return;
        }
    }

    foreach (i; 1..N) {
        if (D[A[i]] > D[A[i-1]]) {
            order[A[i]] = 0;
        } else {
            order[A[i]] = order[A[i-1]] + 1;
        }
    }

    foreach (i; 0..N-1) {
        if (D[A[i]] == D[A[i+1]] && order[P[A[i]]] > order[P[A[i+1]]]) {
            writeln("No");
            return;
        }
    }

    writeln("Yes");
}

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

void main ()
{
	int n;
	while (readf (" %s", &n) > 0)
	{
		auto a = new int [] [n];
		foreach (i; 0..n - 1)
		{
			int u, v;
			readf (" %s %s", &u, &v);
			u -= 1;
			v -= 1;
			a[u] ~= v;
			a[v] ~= u;
		}
		readln;
		auto p = readln.splitter.map !(to !(int)).array;
		p[] -= 1;

		auto d = new int [n];
		auto r = new int [n];

		void recur (int v, int p, int depth)
		{
			d[v] = depth;
			r[v] = p;
			foreach (u; a[v])
			{
				if (u != p)
				{
					recur (u, v, depth + 1);
				}
			}
		}

		recur (0, n, 0);

		bool ok = true;
		scope (exit) {writeln (ok ? "Yes" : "No");}
		foreach (i; 1..n)
		{
			ok &= (d[p[i - 1]] <= d[p[i]]);
		}
		if (!ok)
		{
			continue;
		}

		auto q = new int [n];
		foreach (i, c; p)
		{
			q[c] = i;
		}
		foreach (j; 2..n)
		{
			int i = j - 1;
			auto u = p[i];
			auto v = p[j];
			if (r[u] != r[v])
			{
				ok &= (q[r[u]] < q[r[v]]);
			}
		}
	}
}

import core.bitop;
import std.algorithm;
import std.array;
import std.bitmanip;
import std.container;
import std.conv;
import std.datetime;
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()
{
    int n;
    readf("%s", &n);
    readln;

    auto g = new int[][] (n+1);
    foreach (_; 0 .. n-1) {
        int x, y;
        readf("%s %s", &x, &y);
        readln;

        g[x] ~= y;
        g[y] ~= x;
    }

    auto ord = readln.chomp.split.map!(to!int).array;
    if (ord.front != 1) {
        writeln("No");
        return;
    }

    auto nxt = make!(DList!(RedBlackTree!int));
    nxt ~= make!RedBlackTree(g[1]);
    foreach (e; ord.dropOne) {
        while (!nxt.empty && e !in nxt.front) {
            nxt.removeFront;
        }
        if (nxt.empty) {
            writeln("No");
            return;
        }

        nxt ~= make!RedBlackTree(g[e]);
    }

    writeln("Yes");
}

import core.bitop;
import std.algorithm;
import std.array;
import std.bitmanip;
import std.container;
import std.conv;
import std.datetime;
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()
{
    int n;
    readf("%s", &n);
    readln;

    auto g = new int[][] (n+1);
    foreach (_; 0 .. n-1) {
        int x, y;
        readf("%s %s", &x, &y);
        readln;

        g[x] ~= y;
        g[y] ~= x;
    }

    auto ord = readln.chomp.split.map!(to!int).array;
    if (ord.front != 1) {
        writeln("No");
        return;
    }

    auto vis = new bool[] (n+1);
    auto nxt = make!(DList!(RedBlackTree!int));
    vis[1] = true;
    nxt ~= make!RedBlackTree(g[1]);
    foreach (e; ord.dropOne) {
        if (!e in nxt.front) {
            writeln("No");
            return;
        }
        nxt.front.removeKey(e);

        vis[e] = true;
        nxt ~= make!(RedBlackTree!int);
        foreach (u; g[e]) if (!vis[u]) nxt.back.insert(u);

        if (nxt.front.empty()) nxt.removeFront();
    }

    writeln("Yes");
}

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

void main ()
{
	int n;
	while (readf (" %s", &n) > 0)
	{
		auto a = new int [] [n];
		foreach (i; 0..n - 1)
		{
			int u, v;
			readf (" %s %s", &u, &v);
			u -= 1;
			v -= 1;
			a[u] ~= v;
			a[v] ~= u;
		}
		readln;
		auto p = readln.splitter.map !(to !(int)).array;
		p[] -= 1;

		auto d = new int [n];
		auto r = new int [n];

		void recur (int v, int p, int depth)
		{
			d[v] = depth;
			r[v] = p;
			foreach (u; a[v])
			{
				if (u != p)
				{
					recur (u, v, depth + 1);
				}
			}
		}

		recur (0, n, 0);

		bool ok = true;
		scope (exit) {writeln (ok ? "Yes" : "No");}
		foreach (i; 1..n)
		{
			ok &= (d[p[i - 1]] <= d[p[i]]);
		}
		if (!ok)
		{
			continue;
		}
		continue;

		auto q = new int [n];
		foreach (i, c; p)
		{
			q[c] = i;
		}
		foreach (j; 2..n)
		{
			int i = j - 1;
			auto u = p[i];
			auto v = p[j];
			if (r[u] != r[v])
			{
				ok &= (q[r[u]] < q[r[v]]);
			}
		}
	}
}


import std.stdio, std.conv, std.string, std.array, std.range, std.algorithm, std.container;
import std.math, std.random, std.bigint, std.datetime, std.format;
void main(string[] args){ if(args.length > 1) if(args[1] == "-debug") DEBUG = 1; solve(); } bool DEBUG = 0;
void log(A ...)(lazy A a){ if(DEBUG) print(a); }
void print(){ writeln(""); } void print(T)(T t){ writeln(t); } void print(T, A ...)(T t, A a){ write(t, " "), print(a); }
string unsplit(T)(T xs){ return xs.array.to!(string[]).join(" "); }
string scan(){ static string[] ss; while(!ss.length) ss = readln.chomp.split; string res = ss[0]; ss.popFront; return res; }
T scan(T)(){ return scan.to!T; } T[] scan(T)(int n){ return n.iota.map!(i => scan!T()).array; }
T lowerTo(T)(ref T x, T y){ if(x > y) x = y; return x; } T raiseTo(T)(ref T x, T y){ if(x < y) x = y; return x; }

// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- //

void solve(){
    foreach(_; 0 .. scan!int){
        long x = scan!long;
        print(1, x - 1);
    }
}

import std.stdio;
int main()
{
	int t=0;
	readf(" %d", &t);
	for (int i=0; i<t; i++)
	{
		int a=0;
		readf(" %d", &a);
		writeln(1);
		writeln(a-1);
	}
	return 0;
}


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

int [] solve (bool [] s)
{
	if (s.length < 2)
	{
		return [];
	}
	auto res = solve (s[0..$ - 1]);
	if (s[$ - 2] == s[$ - 1])
	{
		return res ~ 0;
	}
	else
	{
		reverse (s[0..$ - 1]);
		return res ~ 1;
	}
}

void main ()
{
	string s;
	while ((s = readln.strip) != "")
	{
		auto t = s.map !(c => c == 'b').array ~ true;
		writefln ("%(%s %)", solve (t));
	}
}

import std.range;
import std.stdio;
import std.string;

void main ()
{
	string s;
	while ((s = readln.strip) != "")
	{
		auto n = s.length;
		int last = 'b';
		int [] ans;
		foreach_reverse (c; s)
		{
			if (c == last)
			{
				ans ~= 0;
			}
			else
			{
				ans ~= 1;
				last = 'a' + 'b' - last;
			}
		}
		writefln ("%(%s %)", ans.retro);
	}
}


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

void get(Args...)(ref Args args)
{
    import std.traits, std.meta, std.typecons;

    static if (Args.length == 1) {
        alias Arg = Args[0];

        static if (isArray!Arg) {
          static if (isSomeChar!(ElementType!Arg)) {
            args[0] = readln.chomp.to!Arg;
          } else {
            args[0] = readln.split.to!Arg;
          }
        } else static if (isTuple!Arg) {
            auto input = readln.split;
            static foreach (i; 0..Fields!Arg.length) {
                args[0][i] = input[i].to!(Fields!Arg[i]);
            }
        } else {
            args[0] = readln.chomp.to!Arg;
        }
    } else {
        auto input = readln.split;
        assert(input.length == Args.length);

        static foreach (i; 0..Args.length) {
            args[i] = input[i].to!(Args[i]);
        }
    }
}

void get_lines(Args...)(size_t N, ref Args args)
{
    import std.traits, std.range;

    static foreach (i; 0..Args.length) {
        static assert(isArray!(Args[i]));
        args[i].length = N;
    }

    foreach (i; 0..N) {
        static if (Args.length == 1) {
            get(args[0][i]);
        } else {
            auto input = readln.split;
            static foreach (j; 0..Args.length) {
                args[j][i] = input[j].to!(ElementType!(Args[j]));
            }
        }
    }
}

void main()
{
    int T; get(T);
    while (T--) {
        int N; get(N);
        int[] AA; get(AA);
        sort(AA);
        foreach (i; 0..N*2-1) {
            int[][int] memo;
            foreach_reverse (j, a; AA[0..$-1]) if (i != j) memo[a] ~= j.to!int;
            auto aa = new int[](N);
            aa[0] = AA[$-1];
            auto bb = new int[](N);
            bb[0] = AA[i];
            auto j = N*2 - 1;
            if (i == j) --j;
            auto fs = new bool[](N * 2);
            fs[$-1] = fs[i] = true;
            foreach (k; 1..N) {
                auto x = aa[k-1];
                while (fs[j]) --j;
                auto a = AA[j];
                memo[a].popFront();
                fs[j] = true;
                --j;
                auto b = x - a;
                if (b !in memo || memo[b].empty) goto ng;
                fs[memo[b].front] = true;
                memo[b].popFront();
                aa[k] = a;
                bb[k] = b;
            }
            writeln("YES\n", aa[0] + bb[0]);
            foreach (k; 0..N) writeln(aa[k], " ", bb[k]);
            goto ok;
            ng:
        }
        writeln("NO");
        continue;
        ok:
    }
}

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

immutable int limit = 10 ^^ 6 + 1;

void main ()
{
	auto tests = readln.strip.to !(int);
	foreach (test; 0..tests)
	{
		auto n = readln.strip.to !(int);
		auto a = readln.splitter.map !(to !(int)).array;
		sort (a);
		RedBlackTree !(int, q{a < b}, true) t;

		int [2] [] solve (int lo, int hi)
		{
			int [2] [] answer = [[lo, hi]];
			int cur = hi;
			foreach (j; 0..n - 1)
			{
				auto two = t.back;
				t.removeBack ();
				auto one = cur - two;
				if (one !in t)
				{
					return null;
				}
				t.removeKey (one);
				answer ~= [one, two];
				cur = two;
			}
			return answer;
		}

		auto hi = a.back;
		a.popBack ();
		auto t0 = redBlackTree !(true, int) (a);
		int [2] [] answer;
		foreach (ref b; a)
		{
			t = t0.dup;
			t.removeKey (b);
			answer = solve (b, hi);
			if (answer !is null)
			{
				break;
			}
		}

		if (answer !is null)
		{
			writeln ("YES");
			writeln (answer.front[].sum);
			writefln !("%(%(%s %)\n%)") (answer);
		}
		else
		{
			writeln ("NO");
		}
	}
}

import core.bitop, std.bitmanip;
import core.checkedint;
import std.algorithm, std.functional, std.meta;
import std.array, std.container;
import std.bigint;
import std.conv;
import std.math, std.numeric;
import std.range, std.range.interfaces;
import std.stdio, std.string;
import std.ascii, std.typecons;

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

    while (t--) {
        auto n = readln.chomp.to!int;
        auto arr = readln.chomp.split.map!(to!int).array;

        arr.sort();

        bool found = false;
        foreach (start; 0 .. 2*n - 1) {
            int[int] cnt;
            foreach (e; arr) { ++cnt[e]; }
            Tuple!(int, int)[] result;

            int x = arr[2*n-1] + arr[start];
            int pos = 2*n-1;
            while (pos >= 0) {
                if (cnt[arr[pos]] == 0) {
                    --pos;
                    continue;
                }

                int now = arr[pos];
                --cnt[now];

                int need = x - now;
                debug { writeln("pos ", pos, " now: ", now, " need: ", need); }
                if (need !in cnt || cnt[need] == 0) {
                    break;
                }

                --cnt[need];
                result ~= tuple(need, now);

                x = now;

                --pos;
            }

            if (result.length == n) {
                writeln("YES");
                writeln(result[0][0] + result[0][1]);
                foreach (r; result) { writeln(r[0], ' ', r[1]); }
                found = true;
                break;
            }
        }

        if (!found) { writeln("NO"); }
    }
}

import core.bitop, std.bitmanip;
import core.checkedint;
import std.algorithm, std.functional, std.meta;
import std.array, std.container;
import std.bigint;
import std.conv;
import std.math, std.numeric;
import std.range, std.range.interfaces;
import std.stdio, std.string;
import std.ascii, std.typecons;

void main()
{
    immutable int MAXN = 10 ^^ 6;

    auto cnt = new int[] (MAXN + 23);

    auto t = readln.chomp.to!int;

    while (t--) {
        auto n = readln.chomp.to!int;
        auto arr = readln.chomp.split.map!(to!int).array;

        arr.sort();

        bool found = false;
        foreach (start; 0 .. 2*n - 1) {
            foreach (e; arr) { cnt[e] = 0; }
            foreach (e; arr) { ++cnt[e]; }
            Tuple!(int, int)[] result;

            int x = arr[2*n-1] + arr[start];
            int pos = 2*n-1;
            while (pos >= 0) {
                if (cnt[arr[pos]] == 0) {
                    --pos;
                    continue;
                }

                int now = arr[pos];
                cnt[now] -= 1;

                int need = x - now;
                debug { writeln("pos ", pos, " now: ", now, " need: ", need); }
                if (cnt[need] == 0) {
                    break;
                }

                --cnt[need];
                result ~= tuple(need, now);

                x = now;

                --pos;
            }

            if (result.length == n) {
                writeln("YES");
                writeln(result[0][0] + result[0][1]);
                foreach (r; result) { writeln(r[0], ' ', r[1]); }
                found = true;
                break;
            }
        }

        if (!found) { writeln("NO"); }
    }
}


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

alias ll = long;
alias rbt = RedBlackTree;
alias sr = SortedRange;
alias tup = Tuple!(long, long);
static string[] inp;
T rd(T = long)(){while(!inp.length) inp = readln.chomp.split; string a = inp[0]; inp.popFront; return a.to!T;}
T[] rdarr(T = long)(T fix = 0){ auto r = readln.chomp.split.to!(T[]); r[] += fix; return r; }

void solve(){
    int n;
    n = rd!int;
    SortedRange!(ll[])[] sectors;
    foreach(i; 0..n){
        sectors ~= sort(rdarr[1..$]);
    }
    // Check each cell in sector left & right
    ll cnt = 0;
    foreach(i; 0..n){
        int l = (i - 1 + n) % n;
        int r = (i + 1) % n;
        ll lold, rold;
        // writeln(sectors[i].length);
        foreach(k; 0..sectors[i].length){
            ll lnew = sectors[l].lowerBound(sectors[i][k]).length;
            ll rnew = sectors[r].lowerBound(sectors[i][k]).length;
            if(k != 0){
                ll lside = lnew - lold;
                ll rside = rnew - rold;
                if(lside != rside) ++cnt;
                /* debug writeln(lside, " | ", rside, " | ", i, " ", k); */
            }
            lold = lnew;
            rold = rnew;
        }
    }
    writeln(cnt);
}

void main(){
    long t = 1;
    /* t = rd; */
    while(t--) solve();
    stdout.flush;
}

import core.bitop, std.bitmanip;
import core.checkedint;
import std.algorithm, std.functional;
import std.array, std.container;
import std.bigint;
import std.conv;
import std.datetime.stopwatch;
import std.math, std.numeric;
import std.range, std.range.interfaces;
import std.stdio, std.string;
import std.typecons;

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

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

        arr[i] = readln.chomp.split.map!(to!int).array.sort().array;
    }

    debug { arr.each!writeln; }

    int ans = 0;
    foreach (i; 0 .. n) {
        int go(int c, ref int st, int e) {
            int ans = 0;
            while (st < arr[c].length && arr[c][st] < e) {
                ++st;
                ++ans;
            }

            return ans;
        }

        int prv = (i - 1 + n) % n;
        int nxt = (i + 1) % n;

        int cidx = 0, pidx = 0, nidx = 0;
        while (cidx < arr[i].length) {
            int cle = go(prv, pidx, arr[i][cidx]);
            int cr = go(nxt, nidx, arr[i][cidx]);

            if (cidx > 0 && cle != cr) {
                ++ans;

                debug { writeln(i, ' ', cidx, ' ', cle, ' ', cr); }
            }

            ++cidx;
        }
    }

    ans.writeln;
}