/*
  Java solution of problem Skiliften
  for NKP2005
  author: P.G.Kluit
  date  : May 2005

 */

import java.io.*;
import java.util.*;

public class ProblemG {
    private static String infile = "g.in";

    public static void main (String [] args){
        //Stopwatch watch = new Stopwatch();
        try{
           if (args.length > 0) // another inputfile can be given
              infile = args[0]; // as command line argument
           InputStream is = new FileInputStream(infile) ;
           IntReader ir = new IntReader(is);
           int no = ir.read(); //System.out.println("cases:" + no);

           for (int k = 0; k < no; k++){
                //watch.start();
                Problem p = Problem.read(ir);
                //Problem p = ProblemQueued.read(ir);
                //Problem p = ProblemListQueued.read(ir);
                //Problem p = ProblemVectorQueued.read(ir);
                p.solve();
                //watch.stop();
                System.out.println(p.getSolution() + "");
                //System.out.println("  duur: " + watch.getDuur() + " ms");
                //p.report();
           }
        }
        catch (IOException iox){
            System.err.println(iox.toString());
        }
    }
}

class Problem{

     public static final byte
      ANYTHING  = 7,
      NOBOTTOM  = 6,
      TOP       = 4,
      NOTOP     = 3,
      MIDDLE    = 2,
      BOTTOM    = 1,
      NOTHING   = 0;

    int answer;
    int breedte, lengte;
    int [][] hoogte;
    byte [][]soort;

    public void solve(){
       for (int x = 0; x < breedte; x++)
         for (int y = 0; y < lengte; y++){
           int minor=0, equal=0, major=0;
           if (x > 0)
             if (hoogte[x-1][y] < hoogte[x][y])
                minor++;
             else if (hoogte[x-1][y] == hoogte[x][y])
                equal++;
             else if (hoogte[x-1][y] > hoogte[x][y])
                major++;
           if (x < breedte - 1)
             if (hoogte[x+1][y] < hoogte[x][y])
                minor++;
             else if (hoogte[x+1][y] == hoogte[x][y])
                equal++;
             else if (hoogte[x+1][y] > hoogte[x][y])
                major++;
           if (y > 0)
             if (hoogte[x][y-1] < hoogte[x][y])
                minor++;
             else if (hoogte[x][y-1] == hoogte[x][y])
                equal++;
             else if (hoogte[x][y-1] > hoogte[x][y])
                major++;
           if (y < lengte - 1)
             if (hoogte[x][y+1] < hoogte[x][y])
                minor++;
             else if (hoogte[x][y+1] == hoogte[x][y])
                equal++;
             else if (hoogte[x][y+1] > hoogte[x][y])
                major++;

           if (equal == 0)
              if (major > 0 && minor > 0)
                 set(x,y, MIDDLE);
              else if (major > 0)
                 set(x,y,  BOTTOM);
              else if (minor > 0)
                 set(x,y,  TOP);
              else // singleton!
                 set (x,y, MIDDLE);
           else
             if (major > 0 && minor > 0)
                 update(x,y,  MIDDLE);
             else if (major > 0)
                update(x,y,  NOTOP);
             else if (minor > 0)
                 update(x,y,  NOBOTTOM);

       }
       //report();
       int toppen = 0;
       int dalen = 0;
       for (int x = 0; x < breedte; x++)
           for (int y = 0; y < lengte; y++){
             if (soort[x][y] == TOP || soort[x][y] == NOBOTTOM){
                 toppen++;
                 update(x,y, NOTHING);
             }
             if (soort[x][y] == BOTTOM|| soort[x][y] == NOTOP){
                 dalen++;
                 update(x,y, NOTHING);
             }
           }
        //report();
        answer = Math.max(toppen, dalen);
        //System.out.println ("toppen : " + toppen + "   " + "dalen : " + dalen);
    }
      boolean set(int x, int y, byte s){
          byte oldsoort = soort[x][y];
          byte newsoort = (byte) (oldsoort & s);
          if (newsoort == oldsoort)
            return false;
          soort[x][y] = newsoort;
          return true;
      }

      private void report(){
         for (int x = 0; x < breedte; x++){
           for (int y = 0; y < lengte; y++)
             System.out.print(soort[x][y]  + " ");
           System.out.println();
         }
         System.out.println("-----------");

     }

       void update(int x, int y, byte s){
        //   if (soort[x][y] > s){
        //      soort[x][y] = s;
        if (set(x,y,s)){
              if (x > 0 && hoogte[x-1][y] == hoogte[x][y])
                    update (x-1,y, s);
              if (x < breedte - 1 && hoogte[x+1][y] == hoogte[x][y])
                    update (x+1,y, s);
              if (y > 0 && hoogte[x][y-1] == hoogte[x][y])
                    update (x,y-1, s);
              if (y < lengte - 1 && hoogte[x][y+1] == hoogte[x][y])
                    update (x,y+1, s);
           }
       }


    public int getSolution(){
       return answer;
    }

    void readMe(IntReader ir){
       breedte = ir.read();
       lengte  = ir.read();
       hoogte = new int [breedte][lengte];
       soort = new byte [breedte][lengte];
       for (int x = 0; x < breedte; x++)
         for (int y = 0; y < lengte; y++){
           hoogte[x][y] = ir.read();
           soort[x][y] = ANYTHING;
         }
    }

    static Problem read(IntReader ir){
       Problem p = new Problem();
       p.readMe(ir);
       return p;
    }
}

class ProblemQueued extends Problem{
   CircularQueue q = new CircularQueue();  

      private void enqueue(int x, int y, byte s){
         int [] parm = new int [3];
         parm[0] = x; parm[1] = y; parm[2] = s;
         q.enqueue(parm);
      }

      void update(int x, int y, byte s){
         //System.out.println("-");
         enqueue(x,y,s);
         while (! q.isEmpty()){
            int [] parm = q.dequeue();
            x = parm[0];
            y = parm[1];
            s = (byte) parm[2];
            //if (soort[x][y] > s){
            //  soort[x][y] = s;
              //   if (soort[x][y] > s){
        //      soort[x][y] = s;
        if (set(x,y,s)){
              if (x > 0 && hoogte[x-1][y] == hoogte[x][y])
                    enqueue (x-1,y, s);
              if (x < breedte - 1 && hoogte[x+1][y] == hoogte[x][y])
                    enqueue (x+1,y, s);
              if (y > 0 && hoogte[x][y-1] == hoogte[x][y])
                    enqueue (x,y-1, s);
              if (y < lengte - 1 && hoogte[x][y+1] == hoogte[x][y])
                    enqueue (x,y+1, s);
           }
       }
      }

     static Problem read(IntReader ir){
       Problem p = new ProblemQueued();
       p.readMe(ir);
       return p;
    }
}
class ProblemListQueued extends ProblemQueued{
   ListQueue q = new ListQueue();

     static Problem read(IntReader ir){
       Problem p = new ProblemListQueued();
       p.readMe(ir);
       return p;
    }
}

class ProblemVectorQueued extends ProblemQueued{
   ListQueue q = new ListQueue();

     static Problem read(IntReader ir){
       Problem p = new ProblemVectorQueued();
       p.readMe(ir);
       return p;
    }
}
class IntReader extends StreamTokenizer{
 	public IntReader(InputStream is){
	 	super(new BufferedReader(new InputStreamReader(is)));
	}

	public int read(){
		try{
			int tokentype = nextToken();
		}
		catch(IOException iox){
			System.out.println(iox);
		}
		return (int) nval;
	}
}

class CircularQueue {
   private ListElement last;

   public void enqueue(int[] item){
      if (last != null){
         last.next = new ListElement(item, last.next);
         last = last.next;
      }
      else{
         last = new ListElement(item, null);
         last.next = last;
      }
  }

   public int[] dequeue(){
      int [] antwoord = last.next.value;
      if (last.next == last)
         last = null;
      else
         last.next = last.next.next;
      return antwoord;
   }

   public boolean isEmpty(){
      return last == null;
   }

   class ListElement{
     int [] value;
     ListElement next;

     public ListElement(int [] ob, ListElement next){
       value = ob;
       this.next = next;
     }
   }
}

class ListQueue {
   private LinkedList list = new LinkedList();

   public void enqueue(int[] item){
      list.addLast(item);
   }

   public int[] dequeue(){
      int [] antwoord = (int [])list.getFirst();
      list.removeFirst();
      return antwoord;
   }

   public boolean isEmpty(){
      return list.isEmpty();
   }

}

class VectorQueue {
   private Vector vector = new Vector();

   public void enqueue(int[] item){
      vector.add(item);
   }

   public int[] dequeue(){
      int [] antwoord = (int [])vector.firstElement();
      vector.remove(0);
      return antwoord;
   }

   public boolean isEmpty(){
      return vector.isEmpty();
   }

}
