Skip to main content
Common macros and utility definitions that make competitive programming code more concise and efficient.

Overview

Macros help reduce boilerplate code and make common patterns more readable. This collection includes:
  • Type aliases for common data types
  • Loop macros for cleaner iteration
  • Utility functions for min/max operations
  • Constants and precision helpers
  • Pair and tuple shortcuts

Type Aliases

Integer Types

using uint     = uint32_t;
using uint64   = uint64_t;
using int64    = int64_t;
using f64      = long double;
Usage:
int64 big_number = 1e18;
uint64 unsigned_big = 1e19;
f64 precise = 3.14159265358979323846L;

Pair and Tuple Types

using pii  = pair<int, int>;
using piii = tuple<int, int, int>;
using pll  = pair<int64_t, int64_t>;
using plll = tuple<int64_t, int64_t, int64_t>;

#define F  first
#define S  second
Usage:
pii point = {3, 5};
cout << point.F << " " << point.S << "\n";  // 3 5

piii triple = {1, 2, 3};
auto [x, y, z] = triple;

pll big_pair = {1000000000LL, 2000000000LL};

vector<pii> edges = {{1, 2}, {2, 3}, {3, 4}};
for(auto [u, v] : edges) {
    cout << u << " -> " << v << "\n";
}

Constants

Infinity Values

const int     inf    = int(1e9);
const int64_t inf64  = int64_t(1e18);
const int N = int(1e5);
const int M = int(1e5);
const int K = int(1e5);
Usage:
vector<int> dist(n, inf);
dist[0] = 0;

int64 result = inf64;
for(int i = 0; i < n; i++) {
    result = min(result, compute(i));
}

Infinity Macro

#define infinity while(1)
Usage:
infinity {
    // Infinite loop
    if(condition) break;
}

Unreachable Assertion

#define unreachable assert(false && "Unreachable");
Usage:
switch(type) {
    case TYPE_A: handle_a(); break;
    case TYPE_B: handle_b(); break;
    default: unreachable
}

Loop Macros

For Loop Variants

#define overload4(a, b, c, d, e, ...) e

#define for1(a) for(int i = 0; i < int(a); ++i)
#define for2(i, a) for(int i = 0; i < int(a); ++i)
#define for3(i, a, b) for(int i = int(a); i <= int(b); ++i)
#define for4(i, a, b, c) for(int i = int(a); i <= int(b); i += int(c))

#define rof1(a) for(int i = int(a)-1; i >= 0; --i)
#define rof2(i, a) for(int i = int(a)-1; i >= 0; --i)
#define rof3(i, a, b) for(int i = int(b); i >= int(a); --i)
#define rof4(i, a, b, c) for(int i = int(b); i >= int(a); i -= int(c))

#define forn(...) overload4(__VA_ARGS__, for4, for3, for2, for1)(__VA_ARGS__)
#define rof(...)  overload4(__VA_ARGS__, rof4, rof3, rof2, rof1)(__VA_ARGS__)
Features:
  • Overloaded macros that adapt to the number of arguments
  • Default variable name i when not specified
  • Forward iteration with forn
  • Reverse iteration with rof

Usage Examples

Forward Loops

// forn(n) - loop from 0 to n-1 with variable i
forn(5) {
    cout << i << " ";  // 0 1 2 3 4
}
cout << "\n";

// forn(j, n) - loop from 0 to n-1 with variable j
forn(j, 5) {
    cout << j << " ";  // 0 1 2 3 4
}
cout << "\n";

// forn(i, a, b) - loop from a to b (inclusive)
forn(i, 1, 5) {
    cout << i << " ";  // 1 2 3 4 5
}
cout << "\n";

// forn(i, a, b, step) - loop from a to b with step
forn(i, 0, 10, 2) {
    cout << i << " ";  // 0 2 4 6 8 10
}
cout << "\n";

Reverse Loops

// rof(n) - loop from n-1 to 0 with variable i
rof(5) {
    cout << i << " ";  // 4 3 2 1 0
}
cout << "\n";

// rof(j, n) - loop from n-1 to 0 with variable j
rof(j, 5) {
    cout << j << " ";  // 4 3 2 1 0
}
cout << "\n";

// rof(i, a, b) - loop from b to a (inclusive)
rof(i, 1, 5) {
    cout << i << " ";  // 5 4 3 2 1
}
cout << "\n";

// rof(i, a, b, step) - loop from b to a with step
rof(i, 0, 10, 2) {
    cout << i << " ";  // 10 8 6 4 2 0
}
cout << "\n";

Practical Examples

vector<int> arr = {1, 2, 3, 4, 5};

// Sum array elements
int sum = 0;
forn(arr.size()) {
    sum += arr[i];
}

// Reverse array
forn(i, 0, arr.size()/2 - 1) {
    swap(arr[i], arr[arr.size() - 1 - i]);
}

// Fill 2D array
vector<vector<int>> matrix(n, vector<int>(m));
forn(i, n) {
    forn(j, m) {
        matrix[i][j] = i * m + j;
    }
}

// Traverse backwards
rof(arr.size()) {
    cout << arr[i] << " ";
}

Min/Max Utilities

Update if Better

template <class T, class S>
inline bool xmax(T &a, const S &b) {
    return (a < b ? a = b, 1 : 0);
}

template <class T, class S>
inline bool xmin(T &a, const S &b) {
    return (a > b ? a = b, 1 : 0);
}
Features:
  • Updates a if b is better
  • Returns true if update happened
  • Useful in DP and graph algorithms

Usage Examples

int maxVal = -inf;
forn(arr.size()) {
    if(xmax(maxVal, arr[i])) {
        cout << "New max: " << maxVal << "\n";
    }
}

int minVal = inf;
forn(arr.size()) {
    if(xmin(minVal, arr[i])) {
        cout << "New min: " << minVal << "\n";
    }
}

// Dijkstra's algorithm
if(xmin(dist[v], dist[u] + w)) {
    pq.push({dist[v], v});
}

// Dynamic programming
forn(i, 1, n) {
    xmax(dp[i], dp[i-1] + arr[i]);  // Maximum subarray
}

Precision Control

#define precise(n, k) fixed << setprecision(k) << n

// Alternative: Set globally at main()
// cout << fixed << setprecision(9);
Usage:
double pi = 3.14159265358979323846;

cout << precise(pi, 2) << "\n";   // 3.14
cout << precise(pi, 5) << "\n";   // 3.14159
cout << precise(pi, 10) << "\n";  // 3.1415926536

// Set globally for entire program
int main() {
    cout << fixed << setprecision(9);
    
    double x = 1.0 / 3.0;
    cout << x << "\n";  // 0.333333333
    
    return 0;
}

Pragma Optimizations

// Reference: https://codeforces.com/blog/entry/96344
#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt")
Features:
  • Aggressive compiler optimizations
  • SIMD vectorization support
  • Useful for tight time limits
Use pragma optimizations carefully. They can sometimes cause issues with certain judges or compilers.
Usage:
#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt")

#include <bits/stdc++.h>
using namespace std;

int main() {
    // Your optimized code here
    return 0;
}

Complete Template

Here’s a complete template combining all useful macros:
#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt")

#include <bits/stdc++.h>
using namespace std;

// Type aliases
using uint     = uint32_t;
using uint64   = uint64_t;
using int64    = int64_t;
using f64      = long double;

using pii  = pair<int, int>;
using piii = tuple<int, int, int>;
using pll  = pair<int64_t, int64_t>;
using plll = tuple<int64_t, int64_t, int64_t>;

#define F  first
#define S  second

// Constants
const int     inf    = int(1e9);
const int64_t inf64  = int64_t(1e18);
const int N = int(1e5);
const int M = int(1e5);
const int K = int(1e5);

#define infinity while(1)
#define unreachable assert(false && "Unreachable");

// Loop macros
#define overload4(a, b, c, d, e, ...) e
#define for1(a) for(int i = 0; i < int(a); ++i)
#define for2(i, a) for(int i = 0; i < int(a); ++i)
#define for3(i, a, b) for(int i = int(a); i <= int(b); ++i)
#define for4(i, a, b, c) for(int i = int(a); i <= int(b); i += int(c))
#define rof1(a) for(int i = int(a)-1; i >= 0; --i)
#define rof2(i, a) for(int i = int(a)-1; i >= 0; --i)
#define rof3(i, a, b) for(int i = int(b); i >= int(a); --i)
#define rof4(i, a, b, c) for(int i = int(b); i >= int(a); i -= int(c))
#define forn(...) overload4(__VA_ARGS__, for4, for3, for2, for1)(__VA_ARGS__)
#define rof(...)  overload4(__VA_ARGS__, rof4, rof3, rof2, rof1)(__VA_ARGS__)

// Min/Max utilities
template <class T, class S>
inline bool xmax(T &a, const S &b) {
    return (a < b ? a = b, 1 : 0);
}

template <class T, class S>
inline bool xmin(T &a, const S &b) {
    return (a > b ? a = b, 1 : 0);
}

// Precision
#define precise(n, k) fixed << setprecision(k) << n

void solve() {
    // Your solution here
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int t = 1;
    // cin >> t;
    
    while(t--) {
        solve();
    }
    
    return 0;
}

Usage Best Practices

Choose meaningful variable names in loops: Use i, j, k for different nested levels
// Good
forn(i, n) {
    forn(j, m) {
        matrix[i][j] = 0;
    }
}

// Confusing
forn(n) {
    forn(m) {
        matrix[i][i] = 0;  // Both use 'i'
    }
}
Use xmax/xmin for cleaner update logic
// Instead of:
if(arr[i] > maxVal) {
    maxVal = arr[i];
    cout << "Updated!\n";
}

// Use:
if(xmax(maxVal, arr[i])) {
    cout << "Updated!\n";
}
Set precision once in main() for consistency
int main() {
    cout << fixed << setprecision(9);
    // Now all floating point output uses 9 decimal places
}

When to Use Macros

Good Use Cases

  • Competitive programming: Speed and conciseness matter
  • Type aliases: Make code more readable
  • Loop patterns: Reduce repetitive boilerplate
  • Constants: Avoid magic numbers

Avoid in Production Code

  • Macros can hide bugs: No type checking
  • Hard to debug: Preprocessor expands before compilation
  • Name conflicts: Macros don’t respect namespaces
  • Modern alternatives: Use templates, constexpr, auto

Common Pitfalls

Loop variable conflicts: Be careful with nested loops using default variable names
// Bad: Both loops use 'i'
forn(5) {
    forn(5) {
        cout << i << " ";  // Which i?
    }
}

// Good: Specify different variables
forn(i, 5) {
    forn(j, 5) {
        cout << i << "," << j << " ";
    }
}
Macro side effects: Expressions are evaluated multiple times
// Bad: function called multiple times
if(xmax(result, expensive_function())) {
    // expensive_function() called twice!
}

// Good: Store result first
int val = expensive_function();
if(xmax(result, val)) {
    // Only called once
}

Alternative Approaches

For production or larger projects, consider modern C++ alternatives:
// Instead of type aliases
auto x = 5;  // int
auto y = 5LL;  // long long

// Instead of loop macros
for(auto x : container) { }  // Range-based for
for(int i = 0; i < n; ++i) { }  // Traditional for

// Instead of xmax/xmin
result = max(result, value);

// Instead of constants
constexpr int INF = 1e9;
constexpr int64_t INF64 = 1e18;

Build docs developers (and LLMs) love