#include <stdio.h>
#include <stdlib.h>
#define BIAS 5
#define TRUE 1
#define FALSE 0
typedef char byte;
typedef unsigned long long LLU;
typedef struct
{
int parent;
byte isLeft;
} Node;
typedef struct
{
int indexInTree;
LLU occurences;
} QueueNode;
void AddElementToQueue(QueueNode* queue, int* right, QueueNode element)
{
queue[(*right)++] = element;
}
QueueNode PopQueue(QueueNode* queue, int* left)
{
return queue[(*left)++];
}
byte IsQueueEmpty(int* left, int* right)
{
if(*left == *right)
return TRUE;
return FALSE;
}
LLU Huffman(Node* tree,
QueueNode* pureQueue,
QueueNode* mergedQueue,
int* leftPureQueue,
int* rightPureQueue,
int* leftMergedQueue,
int* rightMergedQueue,
int n)
{
LLU result = 0;
int i;
int indexToAdd = n;
byte stop = FALSE;
while(!stop)
{
if(IsQueueEmpty(leftPureQueue, rightPureQueue) && !IsQueueEmpty(leftMergedQueue, rightMergedQueue))
{
if(*leftMergedQueue == (*rightMergedQueue) - 1)
{
stop = TRUE;
continue;
}
}
QueueNode* chosenQueueNodes[] = {NULL, NULL, NULL, NULL};
if(*leftPureQueue < (*rightPureQueue))
chosenQueueNodes[0] = &pureQueue[*leftPureQueue];
if(*leftPureQueue < (*rightPureQueue) - 1)
chosenQueueNodes[1] = &pureQueue[*leftPureQueue + 1];
if(*leftMergedQueue < (*rightMergedQueue))
chosenQueueNodes[2] = &mergedQueue[*leftMergedQueue];
if(*leftMergedQueue < (*rightMergedQueue) - 1)
chosenQueueNodes[3] = &mergedQueue[*leftMergedQueue + 1];
int smallestIndex = -1;
int secondSmallest = -1;
byte isSmallest = FALSE;
for(i = 0; i < 4; i++)
{
if(chosenQueueNodes[i] != NULL)
{
isSmallest = FALSE;
if(smallestIndex == -1)
{
isSmallest = TRUE;
}
else
{
if(chosenQueueNodes[smallestIndex]->occurences > chosenQueueNodes[i]->occurences)
{
isSmallest = TRUE;
}
}
if(isSmallest)
{
smallestIndex = i;
}
}
}
for(int i = 0; i < 4; i++)
{
if(i != smallestIndex)
{
if(chosenQueueNodes[i] != NULL)
{
isSmallest = FALSE;
if(secondSmallest == -1)
{
isSmallest = TRUE;
}
else
{
if(chosenQueueNodes[secondSmallest]->occurences > chosenQueueNodes[i]->occurences)
{
isSmallest = TRUE;
}
}
if(isSmallest)
{
secondSmallest = i;
}
}
}
}
QueueNode* child1 = chosenQueueNodes[smallestIndex];
QueueNode* child2 = chosenQueueNodes[secondSmallest];
tree[child1->indexInTree].parent = indexToAdd;
tree[child1->indexInTree].isLeft = TRUE;
tree[child2->indexInTree].parent = indexToAdd;
tree[child2->indexInTree].isLeft = FALSE;
tree[indexToAdd].parent = indexToAdd;
QueueNode queueNode;
queueNode.indexInTree = indexToAdd;
queueNode.occurences = child1->occurences + child2->occurences;
result += queueNode.occurences;
AddElementToQueue(mergedQueue, rightMergedQueue, queueNode);
indexToAdd++;
if(smallestIndex <= 1)
PopQueue(pureQueue, leftPureQueue);
else
PopQueue(mergedQueue, leftMergedQueue);
if(secondSmallest <= 1)
PopQueue(pureQueue, leftPureQueue);
else
PopQueue(mergedQueue, leftMergedQueue);
}
return result;
}
void ShowCharacter(FILE* fout, Node* tree, int indexInTree, int level, LLU number, LLU* finalSol, int* finalLevel, LLU* cache, int* levelCache)
{
if(levelCache[indexInTree] == -1)
{
if(tree[indexInTree].parent == indexInTree)
{
fprintf(fout, "%d %llu\n", level, number);
*finalSol = number;
*finalLevel = level;
}
else
{
ShowCharacter(fout, tree, tree[indexInTree].parent, level + 1, number + ((LLU)tree[indexInTree].isLeft << (LLU)level), finalSol, finalLevel, cache, levelCache);
}
levelCache[indexInTree] = *finalLevel - level;
cache[indexInTree] = (*finalSol) >> level;
}
else
{
*finalLevel = level + levelCache[indexInTree];
*finalSol = number + (cache[indexInTree] << (LLU)level);
fprintf(fout, "%d %llu\n", *finalLevel, *finalSol);
}
}
int main(void)
{
int i;
int n;
Node* tree;
QueueNode* pureQueue = NULL;
int leftPureQueue = 0;
int rightPureQueue = 0;
QueueNode* mergedQueue = NULL;
int leftMergedQueue = 0;
int rightMergedQueue = 0;
LLU* cache;
int* levelCache;
FILE* fin = fopen("huffman.in", "r");
FILE* fout = fopen("huffman.out", "w");
fscanf(fin, "%d", &n);
tree = (Node*)malloc(sizeof(Node) * (n + BIAS) * 2);
pureQueue = (QueueNode*)malloc(sizeof(QueueNode) * (n + BIAS));
mergedQueue = (QueueNode*)malloc(sizeof(Node) * (n + BIAS) * 2);
cache = (LLU*)malloc(sizeof(LLU) * (n + BIAS) * 2);
levelCache = (int*)malloc(sizeof(int) * (n + BIAS) * 2);
for(int i = 0; i < (n + BIAS) * 2; i++)
{
levelCache[i] = -1;
}
for(i = 0; i < n; i++)
{
tree[i].parent = i;
tree[i].isLeft = FALSE;
QueueNode queueNode;
queueNode.indexInTree = i;
fscanf(fin, "%llu", &queueNode.occurences);
AddElementToQueue(pureQueue, &rightPureQueue, queueNode);
}
fprintf(fout, "%llu\n", Huffman(tree, pureQueue, mergedQueue, &leftPureQueue, &rightPureQueue, &leftMergedQueue, &rightMergedQueue, n));
for(int i = 0; i < n; i++)
{
LLU finalSol = 0LL;
int finalLevel = 0;
ShowCharacter(fout, tree, i, 0, 0LL, &finalSol, &finalLevel, cache, levelCache);
}
free(tree);
tree = NULL;
fclose(fin);
fclose(fout);
return 0;
}