public class Main implements java.lang.Runnable { static MyPrintWriter pw = MyPrintWriter.getInstance(); static FastScanner sc = FastScanner.getInstance(); public static void main(java.lang.String[] args) throws java.io.IOException { new Main().run(); Main.pw.flush(); // JavaToCpp.export(); } @java.lang.Override public void run() { int T = Main.sc.nextInt(); for (int TEST = 0; TEST < T; TEST++) { int N = Main.sc.nextInt(); int[] P = Main.sc.nextInts(N); int[] Q = Main.sc.nextInts(N); ArrayUtils.decrementAll(P); ArrayUtils.decrementAll(Q); // dp[i][j] = max(1 + dp[k][l] : k < i, P[k] < P[i], l < j, Q[l] < Q[j]) // = max(1 + f[k][j] : k < i, P[k] < P[i]) // f[i][j] = max(dp[i][l] : l < j, Q[l] < Q[j]) long[][] dp = new long[N][N]; MaxSeg[] fmax = new MaxSeg[N]; MaxSeg[] gmax = new MaxSeg[N]; for (int i = 0; i < N; i++) { fmax[i] = new MaxSeg(N); gmax[i] = new MaxSeg(N); } for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { dp[i][j] = java.lang.Math.max(dp[i][j], 1 + java.lang.Math.max(0, fmax[j].fold(0, P[i]))); dp[i][j] = java.lang.Math.max(dp[i][j], 1 + java.lang.Math.max(0, gmax[j].fold(P[i] + 1, N))); } { // f[i][*]を更新 var seg = SegTreeFactory.max(N); for (int j = 0; j < N; j++) { long fij = seg.fold(0, Q[j]); seg.set(Q[j], dp[i][j]); fmax[j].mul(P[i], fij); } } { // g[i][*]を更新 var seg = SegTreeFactory.max(N); for (int j = 0; j < N; j++) { long gij = seg.fold(Q[j] + 1, N); seg.set(Q[j], dp[i][j]); gmax[j].mul(P[i], gij); } } } Main.pw.println(ArrayUtils.max(dp)); } } } class ArrayUtils { public static void decrementAll(int[] a) { for (int i = 0; i < a.length; i++) { a[i]--; } } public static long max(long[] a) { long ret = java.lang.Long.MIN_VALUE; for (int i = 0; i < a.length; ++i) { ret = java.lang.Math.max(ret, a[i]); } return ret; } public static long max(long[][] a) { long ret = java.lang.Long.MIN_VALUE; for (int i = 0; i < a.length; ++i) { ret = java.lang.Math.max(ret, ArrayUtils.max(a[i])); } return ret; } } class FastScanner { private static FastScanner instance = null; private final java.io.InputStream in = java.lang.System.in; private final byte[] buffer = new byte[1 << 16]; private int ptr = 0; private int buflen = 0; private FastScanner() { } public static FastScanner getInstance() { if (FastScanner.instance == null) { FastScanner.instance = new FastScanner(); } return FastScanner.instance; } private boolean hasNextByte() { if (ptr < buflen) { return true; } ptr = 0; try { buflen = in.read(buffer); } catch (java.io.IOException e) { e.printStackTrace(); } return buflen > 0; } private int readByte() { if (hasNextByte()) { return buffer[ptr++]; } else { return -1; } } private boolean isPrintableChar(int c) { return (33 <= c) && (c <= 126); } public boolean hasNext() { while (hasNextByte() && (!isPrintableChar(buffer[ptr]))) { ptr++; } return hasNextByte(); } public long nextLong() { if (!hasNext()) { throw new java.util.NoSuchElementException(); } long n = 0; boolean minus = false; int b = readByte(); if (b == '-') { minus = true; b = readByte(); } while ((b >= '0') && (b <= '9')) { // n = n * 10 + (b - '0'); n = ((n << 1) + (n << 3)) + (b - '0'); b = readByte(); } return minus ? -n : n; } public int nextInt() { return ((int) (nextLong())); } public int[] nextInts(int n) { int[] a = new int[n]; for (int i = 0; i < n; ++i) { a[i] = nextInt(); } return a; } } @java.lang.SuppressWarnings("hiding") interface LongMonoidStrategy { long identity(); long mul(long a, long b); default long pow(long a, long n) { if (n < 0) { throw new java.lang.AssertionError(); } long ret = identity(); while (n != 0) { if ((n % 2) == 1) { ret = mul(ret, a); } a = mul(a, a); n /= 2; } return ret; } } class MaxSeg extends SegTreelong { // https://atcoder.jp/contests/abc234/submissions/74021821 public MaxSeg(int n) { super(n, java.lang.Long::max, java.lang.Long.MIN_VALUE / 3); } /** * 内部状態を標準出力に出力する。 *
計算量: O(n)
* // 未テスト * * @param n * 要素数 * @param strategy * モノイドの演算および単位元を定義する Strategy */ public SegTreelong(int n, LongMonoidStrategy strategy) { this(n, strategy::mul, strategy.identity()); } /** * モノイド戦略 {@code strategy} と初期配列 {@code a} を用いてセグメント木を構築する。 * *計算量: O(n)
* // 未テスト * * @param a * 初期要素配列 * @param strategy * モノイドの演算および単位元を定義する Strategy */ public SegTreelong(long[] a, LongMonoidStrategy strategy) { this(a.length, strategy); build(a); } /** * 二項演算 {@code op}、単位元 {@code identity}、初期配列 {@code a} を用いてセグメント木を構築する。 * *計算量: O(n)
* // 未テスト * * @param a * 初期要素配列 * @param op * 2項演算 * @param identity * 単位元 */ public SegTreelong(long[] a, java.util.function.LongBinaryOperator op, long identity) { this(a.length, op, identity); build(a); } public void build(long[] a) { for (int i = 0; i < a.length; i++) { v[id(i, i + 1)] = a[i]; } for (int i = n - 1; i >= 1; i--) { v[i] = getOp().applyAsLong(v[2 * i], v[(2 * i) + 1]); } } public void set(int k, long t) { k = id(k, k + 1); v[k] = t; while (k != id(0, n)) { k /= 2; v[k] = getOp().applyAsLong(v[2 * k], v[(2 * k) + 1]); } } public void mul(int k, long t) { set(k, getOp().applyAsLong(v[id(k, k + 1)], t)); } // [a2^k, (a+1)2^k) int id(int a, int b) { int w = b - a; return (n / w) + (a / w); } public long fold(int l, int r) { r = java.lang.Math.min(r, n); l = java.lang.Math.max(l, 0); if ((r - l) <= 0) { return identity; } int ml = l + java.lang.Integer.lowestOneBit(l); int mr = r - java.lang.Integer.lowestOneBit(r); if ((l < ml) && (ml <= r)) { return getOp().applyAsLong(v[id(l, ml)], fold(ml, r)); } else { return getOp().applyAsLong(fold(l, mr), v[id(mr, r)]); } } public long identity() { return identity; } public long get(int i) { return v[id(i, i + 1)]; } public void dump() { java.lang.System.out.println("セグメント木の各要素"); for (int w = 1; w <= n; w *= 2) { for (int i = 0; i < w; ++i) { java.lang.System.out.print((v[i + w] == identity() ? "e" : v[i + w]) + " ".repeat(n == w ? 1 : ((2 * n) / w) - 1)); } java.lang.System.out.println(); } java.lang.System.out.print("v="); for (int i = 0; i < inputN; i++) { long v = get(i); java.lang.System.out.print((v == identity() ? "e" : v) + (i == (inputN - 1) ? "\n" : " ")); } } /** * * @return the op */ public java.util.function.LongBinaryOperator getOp() { return op; } /** * * @param op * the op to set */ public void setOp(java.util.function.LongBinaryOperator op) { this.op = op; } } // --- Original Code --- // import java.io.IOException; // import java.util.Arrays; // // import library.tools.FastScanner; // import library.tools.MergeFiles; // import library.tools.MyPrintWriter; // import library.util.ArrayUtils; // import library.util.segtree.MaxSeg; // import library.util.segtree.SegTreeFactory; // // public class Main implements Runnable { // // static MyPrintWriter pw = MyPrintWriter.getInstance(); // static FastScanner sc = FastScanner.getInstance(); // // public static void main(String[] args) throws IOException { // new Main().run(); // pw.flush(); // MergeFiles.export(); // // JavaToCpp.export(); // } // // @java.lang.Override // public void run() { // int T=sc.nextInt(); // for (int TEST = 0; TEST < T; TEST++) { // int N=sc.nextInt(); // int[]P=sc.nextInts(N); // int[]Q=sc.nextInts(N); // ArrayUtils.decrementAll(P); // ArrayUtils.decrementAll(Q); // // dp[i][j] = max(1 + dp[k][l] : k < i, P[k] < P[i], l < j, Q[l] < Q[j]) // // = max(1 + f[k][j] : k < i, P[k] < P[i]) // // f[i][j] = max(dp[i][l] : l < j, Q[l] < Q[j]) // // long[][]dp=new long[N][N]; // MaxSeg[] fmax=new MaxSeg[N]; // MaxSeg[] gmax=new MaxSeg[N]; // for (int i = 0; i < N; i++) { // fmax[i]=new MaxSeg(N); // gmax[i]=new MaxSeg(N); // } // // for (int i = 0; i < N; i++) { // for (int j = 0; j < N; j++) { // dp[i][j]=Math.max(dp[i][j], 1+Math.max(0, fmax[j].fold(0, P[i]))); // dp[i][j]=Math.max(dp[i][j], 1+Math.max(0, gmax[j].fold(P[i]+1, N))); // } // { // //f[i][*]を更新 // var seg=SegTreeFactory.max(N); // for (int j = 0; j < N; j++) { // long fij=seg.fold(0, Q[j]); // seg.set(Q[j], dp[i][j]); // fmax[j].mul(P[i], fij); // } // // } // { // //g[i][*]を更新 // var seg=SegTreeFactory.max(N); // for (int j = 0; j < N; j++) { // long gij=seg.fold(Q[j]+1, N); // seg.set(Q[j], dp[i][j]); // gmax[j].mul(P[i], gij); // } // } // } // pw.println(ArrayUtils.max(dp)); // } // // } // // void tr(Object... objects) { // System.out.println(Arrays.deepToString(objects)); // } // // } // // // // //