#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

typedef struct _node {
  struct _node* right;
  struct _node* child;
  long lvl;
  long key;
} node;

typedef struct _list {
  node *node;
  struct _list *next;
} list;

void visit_node_post_order(node *q, void (*callback)(node *)) {
  if (!q) {
    return;
  }

  visit_node_post_order(q->child, callback);
  visit_node_post_order(q->right, callback);
  callback(q);
}

void visit_node_pre_order(node *q, void (*callback)(node *)) {
  if (!q) {
    return;
  }

  callback(q);
  visit_node_post_order(q->right, callback);
  visit_node_post_order(q->child, callback);
}


void node_destroy(list *q) {
  void (*func)(node *) = (void (*)(node *))free;
  list *t = q;
  list *prev = NULL;
  while (t) {
    visit_node_post_order(t->node, func);
    prev = t;
    t = t->next;
    free(prev);
  }
}

node* node_create(long key) {
  node *res = (node *)malloc(sizeof(node));
  res->lvl = 0;
  res->key = key;
  res->right = NULL;
  res->child = NULL;
  return res;
}

node* node_union_same_lvl(node* l, node* r) {
  if (!l) {
    return r;
  }

  if (!r) {
    return l;
  }

  if (l->lvl != r->lvl) {
    fprintf(stderr, "L lvl %d and R lvl %d do mismatch. Returning NULL\n", l->lvl, r->lvl);
    return NULL;
  }

  node* item;
  node* subitem;

  if (l->key > r->key) {
    // l main
    item = l;
    subitem = r;
  } else {
    // r main
    item = r;
    subitem = l;
  }

  if (item->child) {
    node *t = item->child;
    while (t->right != NULL) {
      t = t->right;
    }
    t->right = subitem;
  } else {
    item->child = subitem;
  }
  item->lvl++; // we merged two same lvl binomial heap nodes and created on lvl bigger

  return item;
}

void dump_node(node *q) {
  printf("%d ", q->key);
}

void dump_heap(list *q) {
  list *t = q;
  while (t) {
    printf("Binom lvl %d\n", t->node->lvl);
    visit_node_pre_order(t->node, dump_node);
    printf("\n");
    t = t->next;
  }
}

list* node_union(list *q, node *b) {
  list *bl,*a = q, *c;

  if (!q) {
    bl = (list*)malloc(sizeof(list));
    bl->node = b;
    return bl;
  }

  int added = 0;
  bl = a;
  while (a) {
    if (a->node->lvl > b->lvl) { // it a always will be bigger or equal
      list *el = (list*)malloc(sizeof(list));
      el->node = b;
      el->next = a;
      return el;
    } if (a->node->lvl == b->lvl) {
      a->node = node_union_same_lvl(a->node, b);
      bl = a;
      b = a->node;
      a = a->next;
      added++;
    } else {
      bl = a;
      a = a->next;
    }
  }

  if (!added) {
    list *el = (list*)malloc(sizeof(list));
    el->node = b;
    el->next = NULL;
    bl->next = el;
    return q;
  } else {
    return bl;
  }

}

list* node_add(list *q, long key) {
  node *b = node_create(key);

  return node_union(q, b);
}

int node_del(list **q) {
  list *t = *q;
  long maxValue = INT_MIN;
  node *maxTree = NULL;
  
  while (t) {
    if (!maxTree || t->node->key > maxValue) {
      maxValue = t->node->key;
      maxTree = t->node;
    }

    t = t->next;
  }

  // we have max element and tree now

  t = *q;

  if (t->node == maxTree) {
    printf("Removed maxtree is the beginning\n");
    t = t->next;
  } else {
    printf("Removed maxtree is not the beginning\n");
    while (t && t->next && t->next->node != maxTree) {
      t = t->next;
    }

    t->next = t->next->next;
  }

  printf("New list pointer 0x%x\n", t);

  // we removed the maxTree from the list

  node *c = maxTree->child;
  node *b;
  while (c) {
    b = c->right;
    c->right = NULL;
    t = node_union(t, c);
    c = b;
  }

  *q = t;
  
  return maxValue;
}


const int MAX_BUFFER = 0x1000;

int main() {
  char cmd[MAX_BUFFER];
  list *q = NULL;
  while (1) {

    fgets(cmd, MAX_BUFFER, stdin);
    printf("Got command %s\n", cmd);

    if (strlen(cmd) == 0 || cmd[0] == '\n') {
      printf("Finished reading\n");
      break;
    } else if (memcmp(cmd, "ADD", 3) == 0) {
      // handle command add
      int x = atoi(cmd + 4);
       
      q = node_add(q, x);

      printf("Added number: %d\n", x);
  
    } else if (memcmp(cmd, "DEL", 3) == 0) {
      // handle command del
      if (!q) {
        fprintf(stderr, "There is nothing to delete - heap is empty\n");
        continue;
      }
      
      long key = node_del(&q);
      printf("Removed element: %d\n", key);
    } else {
      // handle unknown command
      fprintf(stderr, "Got unknown command %s\n", cmd);
    }

    dump_heap(q);

  }

  if (!q) {
    node_destroy(q);
  }

  return 0;
}
