inlinevoidread(int& ret){ ret = NEG = 0 ; while (CH=getchar() , CH<'!') ; if (CH == '-') NEG = true , CH = getchar() ; while (ret = ret*10+CH-'0' , CH=getchar() , CH>'!') ; if (NEG) ret = -ret ; }
#include <cstring>
#define maxn 2000005LL #define maxe 6000005LL
struct FST { int to , next , w ; } e[maxe] ;
int star[maxn] = {0} , tote = 0 ; voidAddEdge(int u , int v , int w){ truee[++tote].to = v ; e[tote].w = w ; e[tote].next = star[u] ; star[u] = tote ; }
int n , N , M , S , T ;
inlineinthash(int x , int y){ return (x-1)*M+y ; } inlineintblock_up(int x , int y){ return hash(x,y)*2-(x-1)*2 ; } inlineintblock_down(int x , int y){ return hash(x,y)*2-(x-1)*2-1 ; } /* 返回以(x,y)为左上点的上下三角区域标号 */
int i , j , k , u , v ; voidBuild(){ trueread(N) , read(M) ; truen = (N-1)*(M-1)*2 ; S = ++n ; T = ++n ; truefor (i = 1 ; i <= N ; i ++ ) { truetruefor (j = 1 ; j < M ; j ++ ) { truetruetrueread(k) ; truetruetrueu = i>1 ? block_down(i-1,j) : T ; truetruetruev = i<N ? block_up(i,j) : S ; truetruetrueAddEdge(u , v , k) , AddEdge(v , u , k) ; truetrue} true} truefor (i = 1 ; i < N ; i ++ ) { truetruefor (j = 1 ; j <= M ; j ++ ) { truetruetrueread(k) ; truetruetrueu = j>1 ? block_up(i,j-1) : S ; truetruetruev = j<M ? block_down(i,j) : T ; truetruetrueAddEdge(u , v , k) , AddEdge(v , u , k) ; truetrue} true} truefor (i = 1 ; i < N ; i ++ ) { truetruefor (j = 1 ; j < M ; j ++ ) { truetruetrueread(k) ; truetruetrueu = block_up(i,j) ; truetruetruev = block_down(i,j) ; truetruetrueAddEdge(u , v , k) , AddEdge(v , u , k) ; truetrue} true} }
#define sizeque 2000000LL int q[sizeque] , head , tail ; inlineintF(int x){ return ((x%sizeque)+sizeque)%sizeque ; } inlinevoidclear(){ head = 0 , tail = -1 ; } inlineintfront(){ return q[F(head)] ; } inlineintback(){ return q[F(tail)] ; } inlinevoidpush_front(int x){ q[F(--head)] = x ; } inlinevoidpush_back(int x){ q[F(++tail)] = x ; } inlinevoidpop_front(){ head ++ ;} inlinevoidpop_back(){ tail -- ; } inlineboolempty(){ return head > tail ; }