package java.util;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  class TimSort<T> {     
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
      private static final int MIN_MERGE = 32;
      
 
      private final T[] a;
      
 
 
      private final Comparator<? super T> c;
      
 
 
      private static final int  MIN_GALLOP = 7;
      
 
 
 
      private int minGallop = MIN_GALLOP;
      
 
 
 
 
 
 
      private static final int INITIAL_TMP_STORAGE_LENGTH = 256;
      
 
 
 
 
      private T[] tmp;     private int tmpBase;      private int tmpLen;  
      
 
 
 
 
 
 
 
 
      private int stackSize = 0;       private final int[] runBase;     private final int[] runLen;
      
 
 
 
 
 
 
 
 
      private TimSort(T[] a, Comparator<? super T> c, T[] work, int workBase, int workLen) {         this.a = a;         this.c = c;
                            int len = a.length;         int tlen = (len < 2 * INITIAL_TMP_STORAGE_LENGTH) ?             len >>> 1 : INITIAL_TMP_STORAGE_LENGTH;                           if (work == null || workLen < tlen || workBase + tlen > work.length) {                          @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"})             T[] newArray = (T[])java.lang.reflect.Array.newInstance                 (a.getClass().getComponentType(), tlen);             tmp = newArray;             tmpBase = 0;             tmpLen = tlen;         }         else {             tmp = work;             tmpBase = workBase;             tmpLen = workLen;         }
          
 
 
 
 
 
 
 
 
 
 
 
 
 
 
          int stackLen = (len <    120  ?  5 :                         len <   1542  ? 10 :                         len < 119151  ? 24 : 49);         runBase = new int[stackLen];         runLen = new int[stackLen];     }
      
 
 
 
 
      
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
      static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c,                          T[] work, int workBase, int workLen) {         assert c != null && a != null && lo >= 0 && lo <= hi && hi <= a.length;                  int nRemaining  = hi - lo;                  if (nRemaining < 2)             return;  
                            if (nRemaining < MIN_MERGE) {                          int initRunLen = countRunAndMakeAscending(a, lo, hi, c);                          binarySort(a, lo, hi, lo + initRunLen, c);             return;         }
          
 
 
 
                   TimSort<T> ts = new TimSort<>(a, c, work, workBase, workLen);                  int minRun = minRunLength(nRemaining);         do {                                       int runLen = countRunAndMakeAscending(a, lo, hi, c);
                                                     if (runLen < minRun) {                 int force = nRemaining <= minRun ? nRemaining : minRun;                                  binarySort(a, lo, lo + force, lo + runLen, c);                 runLen = force;             }
                                        ts.pushRun(lo, runLen);                          ts.mergeCollapse();
                                        lo += runLen;             nRemaining -= runLen;         } while (nRemaining != 0);
                            assert lo == hi;                  ts.mergeForceCollapse();                  assert ts.stackSize == 1;     }
      
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
           @SuppressWarnings("fallthrough")     private static <T> void binarySort(T[] a, int lo, int hi, int start,                                        Comparator<? super T> c) {                  assert lo <= start && start <= hi;         if (start == lo)             start++;                  for ( ; start < hi; start++) {                          T pivot = a[start];
                                                     int left = lo;             int right = start;             assert left <= right;             
 
 
 
                           while (left < right) {                 int mid = (left + right) >>> 1;                 if (c.compare(pivot, a[mid]) < 0)                     right = mid;                 else                     left = mid + 1;             }             assert left == right;
              
 
 
 
 
 
                           int n = start - left;                                         switch (n) {                                  case 2:  a[left + 2] = a[left + 1];                 case 1:  a[left + 1] = a[left];                          break;                                  default: System.arraycopy(a, left, a, left + 1, n);             }                          a[left] = pivot;         }     }
      
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
      private static <T> int countRunAndMakeAscending(T[] a, int lo, int hi,                                                     Comparator<? super T> c) {         assert lo < hi;                  int runHi = lo + 1;         if (runHi == hi)             return 1;
                   if (c.compare(a[runHi++], a[lo]) < 0) {              while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) < 0)                 runHi++;                                       reverseRange(a, lo, runHi);         } else {                                           while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) >= 0)                 runHi++;         }
          return runHi - lo;     }
      
 
 
 
 
 
      private static void reverseRange(Object[] a, int lo, int hi) {         hi--;                  while (lo < hi) {             Object t = a[lo];             a[lo++] = a[hi];             a[hi--] = t;         }     }
      
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
      private static int minRunLength(int n) {         assert n >= 0;         int r = 0;               while (n >= MIN_MERGE) {             r |= (n & 1);             n >>= 1;         }         return n + r;     }
      
 
 
 
 
 
      private void pushRun(int runBase, int runLen) {         this.runBase[stackSize] = runBase;         this.runLen[stackSize] = runLen;         stackSize++;     }
      
 
 
 
 
 
 
 
 
 
 
 
 
      private void mergeCollapse() {         while (stackSize > 1) {             int n = stackSize - 2;             if (n > 0 && runLen[n-1] <= runLen[n] + runLen[n+1]) {                 if (runLen[n - 1] < runLen[n + 1])                     n--;                 mergeAt(n);             } else if (runLen[n] <= runLen[n + 1]) {                 mergeAt(n);             } else {                 break;              }         }     }
      
 
 
 
      private void mergeForceCollapse() {         while (stackSize > 1) {             int n = stackSize - 2;             if (n > 0 && runLen[n - 1] < runLen[n + 1])                 n--;             mergeAt(n);         }     }
      
 
 
 
 
 
 
 
      private void mergeAt(int i) {         assert stackSize >= 2;         assert i >= 0;         assert i == stackSize - 2 || i == stackSize - 3;
          int base1 = runBase[i];         int len1 = runLen[i];         int base2 = runBase[i + 1];         int len2 = runLen[i + 1];                  assert len1 > 0 && len2 > 0;         assert base1 + len1 == base2;
          
 
 
 
 
 
          runLen[i] = len1 + len2;         if (i == stackSize - 3) {             runBase[i + 1] = runBase[i + 2];             runLen[i + 1] = runLen[i + 2];         }         stackSize--;
          
 
 
                   int k = gallopRight(a[base2], a, base1, len1, 0, c);         assert k >= 0;                           base1 += k;         len1 -= k;                  if (len1 == 0)             return;
          
 
 
                   len2 = gallopLeft(a[base1 + len1 - 1], a, base2, len2, len2 - 1, c);                           assert len2 >= 0;         if (len2 == 0)             return;
                                     if (len1 <= len2)             mergeLo(base1, len1, base2, len2);         else             mergeHi(base1, len1, base2, len2);     }
      
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
      private static <T> int gallopLeft(T key, T[] a, int base, int len, int hint,                                       Comparator<? super T> c) {         assert len > 0 && hint >= 0 && hint < len;         int lastOfs = 0;         int ofs = 1;                  if (c.compare(key, a[base + hint]) > 0) {                          int maxOfs = len - hint;                          while (ofs < maxOfs && c.compare(key, a[base + hint + ofs]) > 0) {                 lastOfs = ofs;                                  ofs = (ofs << 1) + 1;                                  if (ofs <= 0)                        ofs = maxOfs;             }             if (ofs > maxOfs)                 ofs = maxOfs;
                                        lastOfs += hint;             ofs += hint;         } else {                           final int maxOfs = hint + 1;                          while (ofs < maxOfs && c.compare(key, a[base + hint - ofs]) <= 0) {                 lastOfs = ofs;                 ofs = (ofs << 1) + 1;                 if (ofs <= 0)                        ofs = maxOfs;             }             if (ofs > maxOfs)                 ofs = maxOfs;
                                        int tmp = lastOfs;             lastOfs = hint - ofs;             ofs = hint - tmp;         }                  assert -1 <= lastOfs && lastOfs < ofs && ofs <= len;
          
 
 
 
 
 
          lastOfs++;         while (lastOfs < ofs) {             int m = lastOfs + ((ofs - lastOfs) >>> 1);
              if (c.compare(key, a[base + m]) > 0)                 lastOfs = m + 1;               else                 ofs = m;                   }         assert lastOfs == ofs;             return ofs;     }
      
 
 
 
 
 
 
 
 
 
 
 
 
      private static <T> int gallopRight(T key, T[] a, int base, int len,                                        int hint, Comparator<? super T> c) {         assert len > 0 && hint >= 0 && hint < len;
          int ofs = 1;         int lastOfs = 0;         if (c.compare(key, a[base + hint]) < 0) {                          int maxOfs = hint + 1;             while (ofs < maxOfs && c.compare(key, a[base + hint - ofs]) < 0) {                 lastOfs = ofs;                 ofs = (ofs << 1) + 1;                 if (ofs <= 0)                        ofs = maxOfs;             }             if (ofs > maxOfs)                 ofs = maxOfs;
                           int tmp = lastOfs;             lastOfs = hint - ofs;             ofs = hint - tmp;         } else {                           int maxOfs = len - hint;             while (ofs < maxOfs && c.compare(key, a[base + hint + ofs]) >= 0) {                 lastOfs = ofs;                 ofs = (ofs << 1) + 1;                 if (ofs <= 0)                        ofs = maxOfs;             }             if (ofs > maxOfs)                 ofs = maxOfs;
                           lastOfs += hint;             ofs += hint;         }         assert -1 <= lastOfs && lastOfs < ofs && ofs <= len;
          
 
 
 
          lastOfs++;         while (lastOfs < ofs) {             int m = lastOfs + ((ofs - lastOfs) >>> 1);
              if (c.compare(key, a[base + m]) < 0)                 ofs = m;                       else                 lastOfs = m + 1;           }         assert lastOfs == ofs;             return ofs;     }
      
 
 
 
 
 
 
 
 
 
 
 
 
 
 
      private void mergeLo(int base1, int len1, int base2, int len2) {         assert len1 > 0 && len2 > 0 && base1 + len1 == base2;
                   T[] a = this.a;                   T[] tmp = ensureCapacity(len1);         int cursor1 = tmpBase;          int cursor2 = base2;            int dest = base1;                        System.arraycopy(a, base1, tmp, cursor1, len1);
                            a[dest++] = a[cursor2++];                  if (--len2 == 0) {             System.arraycopy(tmp, cursor1, a, dest, len1);             return;         }                                    if (len1 == 1) {             System.arraycopy(a, cursor2, a, dest, len2);             a[dest + len2] = tmp[cursor1];              return;         }
          Comparator<? super T> c = this.c;                    int minGallop = this.minGallop;         outer:         while (true) {             int count1 = 0;              int count2 = 0; 
              
 
 
                           do {                 assert len1 > 1 && len2 > 0;                 if (c.compare(a[cursor2], tmp[cursor1]) < 0) {                     a[dest++] = a[cursor2++];                     count2++;                     count1 = 0;                                          if (--len2 == 0)                         break outer;                 } else {                     a[dest++] = tmp[cursor1++];                     count1++;                     count2 = 0;                     if (--len1 == 1)                         break outer;                 }                              } while ((count1 | count2) < minGallop);
              
 
 
 
                           do {                 assert len1 > 1 && len2 > 0;                 count1 = gallopRight(a[cursor2], tmp, cursor1, len1, 0, c);                 if (count1 != 0) {                     System.arraycopy(tmp, cursor1, a, dest, count1);                     dest += count1;                     cursor1 += count1;                     len1 -= count1;                                          if (len1 <= 1)                          break outer;                 }                 a[dest++] = a[cursor2++];                 if (--len2 == 0)                     break outer;                                                   count2 = gallopLeft(tmp[cursor1], a, cursor2, len2, 0, c);                 if (count2 != 0) {                     System.arraycopy(a, cursor2, a, dest, count2);                     dest += count2;                     cursor2 += count2;                     len2 -= count2;                     if (len2 == 0)                         break outer;                 }                 a[dest++] = tmp[cursor1++];                 if (--len1 == 1)                     break outer;                                  minGallop--;                          } while (count1 >= MIN_GALLOP | count2 >= MIN_GALLOP);             if (minGallop < 0)                 minGallop = 0;                          minGallop += 2;           }           this.minGallop = minGallop < 1 ? 1 : minGallop;  
                   if (len1 == 1) {             assert len2 > 0;             System.arraycopy(a, cursor2, a, dest, len2);             a[dest + len2] = tmp[cursor1];          } else if (len1 == 0) {                          throw new IllegalArgumentException(                 "Comparison method violates its general contract!");         } else {             assert len2 == 0;             assert len1 > 1;             System.arraycopy(tmp, cursor1, a, dest, len1);         }     }
      
 
 
 
 
 
 
 
 
 
      private void mergeHi(int base1, int len1, int base2, int len2) {         assert len1 > 0 && len2 > 0 && base1 + len1 == base2;
                   T[] a = this.a;          T[] tmp = ensureCapacity(len2);         int tmpBase = this.tmpBase;         System.arraycopy(a, base2, tmp, tmpBase, len2);
          int cursor1 = base1 + len1 - 1;           int cursor2 = tmpBase + len2 - 1;          int dest = base2 + len2 - 1;     
                   a[dest--] = a[cursor1--];         if (--len1 == 0) {             System.arraycopy(tmp, tmpBase, a, dest - (len2 - 1), len2);             return;         }         if (len2 == 1) {             dest -= len1;             cursor1 -= len1;             System.arraycopy(a, cursor1 + 1, a, dest + 1, len1);             a[dest] = tmp[cursor2];             return;         }
          Comparator<? super T> c = this.c;           int minGallop = this.minGallop;         outer:         while (true) {             int count1 = 0;              int count2 = 0; 
              
 
 
              do {                 assert len1 > 0 && len2 > 1;                 if (c.compare(tmp[cursor2], a[cursor1]) < 0) {                     a[dest--] = a[cursor1--];                     count1++;                     count2 = 0;                     if (--len1 == 0)                         break outer;                 } else {                     a[dest--] = tmp[cursor2--];                     count2++;                     count1 = 0;                     if (--len2 == 1)                         break outer;                 }             } while ((count1 | count2) < minGallop);
              
 
 
 
              do {                 assert len1 > 0 && len2 > 1;                 count1 = len1 - gallopRight(tmp[cursor2], a, base1, len1, len1 - 1, c);                 if (count1 != 0) {                     dest -= count1;                     cursor1 -= count1;                     len1 -= count1;                     System.arraycopy(a, cursor1 + 1, a, dest + 1, count1);                     if (len1 == 0)                         break outer;                 }                 a[dest--] = tmp[cursor2--];                 if (--len2 == 1)                     break outer;
                  count2 = len2 - gallopLeft(a[cursor1], tmp, tmpBase, len2, len2 - 1, c);                 if (count2 != 0) {                     dest -= count2;                     cursor2 -= count2;                     len2 -= count2;                     System.arraycopy(tmp, cursor2 + 1, a, dest + 1, count2);                     if (len2 <= 1)                           break outer;                 }                 a[dest--] = a[cursor1--];                 if (--len1 == 0)                     break outer;                 minGallop--;             } while (count1 >= MIN_GALLOP | count2 >= MIN_GALLOP);             if (minGallop < 0)                 minGallop = 0;             minGallop += 2;           }           this.minGallop = minGallop < 1 ? 1 : minGallop;  
          if (len2 == 1) {             assert len1 > 0;             dest -= len1;             cursor1 -= len1;             System.arraycopy(a, cursor1 + 1, a, dest + 1, len1);             a[dest] = tmp[cursor2];           } else if (len2 == 0) {             throw new IllegalArgumentException(                 "Comparison method violates its general contract!");         } else {             assert len1 == 0;             assert len2 > 0;             System.arraycopy(tmp, tmpBase, a, dest - (len2 - 1), len2);         }     }
      
 
 
 
 
 
 
 
      private T[] ensureCapacity(int minCapacity) {                  if (tmpLen < minCapacity) {                                       int newSize = minCapacity;             newSize |= newSize >> 1;             newSize |= newSize >> 2;             newSize |= newSize >> 4;             newSize |= newSize >> 8;             newSize |= newSize >> 16;             newSize++;                          if (newSize < 0)                  newSize = minCapacity;             else                                  newSize = Math.min(newSize, a.length >>> 1);                                       @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"})             T[] newArray = (T[])java.lang.reflect.Array.newInstance                 (a.getClass().getComponentType(), newSize);             tmp = newArray;             tmpLen = newSize;             tmpBase = 0;         }                  return tmp;     } }
   |