#include <iostream>
#include <iomanip>
#include <memory>
#include <vector>
#include <ctime>

static const uint64_t SEED = 0xDEADBEEFull;
static const size_t ROWS = 10000;
static const size_t COLS = 10000;
static const uint32_t COLORS_NUM = 3;

uint32_t LCGRand()
{
    static uint64_t seed = SEED;
    seed = seed * 6364136223846793005 + 1442695040888963407;
    return seed >> 32;
}

struct Node {
	uint32_t color;
	size_t size;
	Node *next;
	Node *prev;
	
	Node() : color(COLORS_NUM), size(0), next(this), prev(this) { }
	
	void PushOut(size_t& max_size) {
		if (next == this) {
			max_size = std::max(max_size, size);
			return;
		}
		next->size += size;
		next->prev = prev;
		prev->next = next;
		next = prev = this;
	}
	
	void LinkTo(Node &other) {
		other.prev->next = next;
		next->prev = other.prev;
		next = &other;
		other.prev = this;
	}
};

int main()
{
	std::vector<Node> scanline(COLS);
	
	size_t max_size = 0;
	
	clock_t start = clock();
	
    for (size_t row = 0; row < ROWS; row++) {
    	for (size_t col = 0; col < COLS; col++) {
    		uint32_t color = LCGRand() % COLORS_NUM;
    		
    		if (scanline[col].color != color) {
    			scanline[col].PushOut(max_size);
    			scanline[col].color = color;
    			scanline[col].size = 1;
    		} else {
    			scanline[col].size++;
    		}
    		
    		if ((col > 0) && (scanline[col - 1].color == color))
    			scanline[col].LinkTo(scanline[col - 1]);
    	}
    }
    
    for (size_t col = 0; col < COLS; col++)
    	scanline[col].PushOut(max_size);
	
    std::cout << "Max block size: " << max_size << std::endl;
    std::cout << "Time: " << (clock() - start) / (CLOCKS_PER_SEC / 1000) << " ms" << std::endl;
    return 0;
}
