int[][] m = process(a);

query(i,j,m,a);

public static int query(int i,int j,int[][] m, int[] a) {

int k = binlog(j-i+1);

return Math.min(a[m[i][k]], a[m[j+1-(1<<k)][k]]);

}

public static int binlog( int bits ) // returns 0 for bits=0

{

int log = 0;

if( ( bits & 0xffff0000 ) != 0 ) { bits >>>= 16; log = 16; }

if( bits >= 256 ) { bits >>>= 8; log += 8; }

if( bits >= 16 ) { bits >>>= 4; log += 4; }

if( bits >= 4 ) { bits >>>= 2; log += 2; }

return log + ( bits >>> 1 );

}

private static int[][] process(int[] a) {

int n = a.length;

int[][] m = new int[n][binlog(n)+1];

//initialize M for the intervals with length 1

for (int i = 0; i < n; i++)

m[i][0] = i;

//compute values from smaller to bigger intervals

for (int j = 1; 1 << j <= n; j++)

for (int i = 0; i + (1 << j) - 1 < n; i++)

if (a[m[i][j - 1]] < a[m[i + (1 << (j - 1))][j - 1]])

m[i][j] = m[i][j - 1];

else

m[i][j] = m[i + (1 << (j - 1))][j - 1];

return m;

}