#include <bits/stdc++.h> // Standard headers
using namespace std; // Standard namespace
// Class to implement N stacks in a single array
int *arr; // The main array to store elements of all N stacks
int *top; // Array to store the top index for each of the N stacks
int *next; // Array to manage linked list for free slots and stack elements
int freeSpot; // Stores the index of the next available free slot in 'arr'
// Constructor: Initializes the multi-stack structure
// N: Number of stacks, S: Total size of the underlying array
arr = new int[S]; // Allocate memory for the main data array
top = new int[N]; // Allocate memory for 'top' pointers of N stacks
next = new int[S]; // Allocate memory for 'next' pointers
// Initialize 'top' array: All stacks are initially empty (-1)
for(int i = 0; i < N; i++) {
// Initialize 'next' array: Create an initial free list
// Each index 'i' points to the next index 'i+1'
for(int i = 0; i < S - 1; i++) {
next[S - 1] = -1; // The last index points to -1, marking end of free list
// Initialize 'freeSpot': The first index (0) is initially available
// Push operation: Pushes element 'X' onto stack 'M' (M is 1-indexed)
bool push(int X, int M) {
// Check for overflow: If freeSpot is -1, no space available
return false; // Stack overflow
// Step 1: Get the index from the free list
// Step 2: Update freeSpot to the next available slot
// Step 3: Insert the data into the allocated spot
// Step 4: Link the new element to the previous top of its stack
// The 'next' of this new element points to the old top
next[index] = top[M - 1]; // M is 1-indexed
// Step 5: Update the 'top' pointer for stack M
// The new element's index becomes the new top
return true; // Push successful
// Pop operation: Pops an element from stack 'M' (M is 1-indexed)
// Check for underflow: If top of stack M is -1, the stack is empty
return -1; // Stack underflow
// Step 1: Get the index of the element to be popped (current top)
// Step 2: Update the 'top' pointer for stack M to the next element down
top[M - 1] = next[index];
// Step 3: Return the popped index to the free list
// The 'next' of this freed index points to the current head of the free list
// Step 4: Update 'freeSpot' to the newly freed index
// Return the popped value
// Destructor to free dynamically allocated memory
// Create an NStack object: 3 stacks (N=3) in a total array size of 6 (S=6)
// Example Push operations (data, stack_number)
if(nst.push(10, 1)) cout << "Pushed 10 to Stack 1: TRUE\n"; else cout << "Pushed 10 to Stack 1: FALSE\n";
if(nst.push(20, 1)) cout << "Pushed 20 to Stack 1: TRUE\n"; else cout << "Pushed 20 to Stack 1: FALSE\n";
if(nst.push(30, 2)) cout << "Pushed 30 to Stack 2: TRUE\n"; else cout << "Pushed 30 to Stack 2: FALSE\n";
if(nst.push(40, 3)) cout << "Pushed 40 to Stack 3: TRUE\n"; else cout << "Pushed 40 to Stack 3: FALSE\n";
if(nst.push(50, 1)) cout << "Pushed 50 to Stack 1: TRUE\n"; else cout << "Pushed 50 to Stack 1: FALSE\n";
if(nst.push(60, 2)) cout << "Pushed 60 to Stack 2: TRUE\n"; else cout << "Pushed 60 to Stack 2: FALSE\n";
// Attempt to push to full array (should overflow)
if(nst.push(70, 1)) cout << "Pushed 70 to Stack 1: TRUE\n"; else cout << "Pushed 70 to Stack 1: FALSE (Overflow)\n";
cout << "\n--- Pop Operations ---\n";
// Example Pop operations (stack_number)
cout << "Popped from Stack 1: " << nst.pop(1) << endl; // Should pop 50
cout << "Popped from Stack 2: " << nst.pop(2) << endl; // Should pop 60
cout << "Popped from Stack 1: " << nst.pop(1) << endl; // Should pop 20
cout << "Popped from Stack 3: " << nst.pop(3) << endl; // Should pop 40
cout << "Popped from Stack 1: " << nst.pop(1) << endl; // Should pop 10
cout << "Popped from Stack 1: " << nst.pop(1) << endl; // Should be -1 (underflow)