Skip to main content
Fast I/O utilities for efficiently reading and writing data in competitive programming, where I/O can be a bottleneck for large datasets.

Overview

In competitive programming, standard I/O can be slow when dealing with large amounts of data. These utilities provide:
  • Fast reading of arrays and containers
  • Fast writing with custom formatting
  • Support for various STL containers
  • Convenient APIs for common operations

Quick Start

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

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n;
    cin >> n;
    
    vector<int> arr;
    read(arr, n);  // Read n integers into vector
    
    write(arr);    // Write entire vector
    
    return 0;
}

Reading Utilities

Read Function

Read n elements into a container starting at a specific position.
template<typename T> // supported for vector, list, forward_list and deque
void read(T &&ref, int n, int start=0) {
    assert(0<=start && 0<=n); 
    ref.resize(start+n);
    for(auto it=next(begin(ref), start); it != end(ref); it++)
        cin >> *it;
}
Parameters:
  • ref: Reference to container (vector, list, deque, forward_list)
  • n: Number of elements to read
  • start: Starting index (default: 0)
Features:
  • Automatically resizes container
  • Works with any type that supports operator>>
  • Includes bounds checking
  • Efficient iterator-based reading

Usage Examples

Read Vector

vector<int> arr;
read(arr, 5);  // Read 5 integers
// Input: 1 2 3 4 5
// Result: arr = {1, 2, 3, 4, 5}

Read with Starting Position

vector<int> arr = {10, 20, 30};
read(arr, 3, 3);  // Read 3 more integers starting at index 3
// Input: 40 50 60
// Result: arr = {10, 20, 30, 40, 50, 60}

Read Different Types

vector<string> words;
read(words, 3);
// Input: hello world test
// Result: words = {"hello", "world", "test"}

vector<double> values;
read(values, 4);
// Input: 3.14 2.71 1.41 1.73
// Result: values = {3.14, 2.71, 1.41, 1.73}

Read List or Deque

list<int> lst;
read(lst, 5);
// Input: 10 20 30 40 50
// Result: lst = {10, 20, 30, 40, 50}

deque<int> dq;
read(dq, 3);
// Input: 1 2 3
// Result: dq = {1, 2, 3}

1-Indexed Arrays

vector<int> arr;
read(arr, 5, 1);  // Reserve index 0, read into indices 1-5
// Input: 10 20 30 40 50
// Result: arr = {0, 10, 20, 30, 40, 50}
// Access: arr[1] = 10, arr[2] = 20, ...

Writing Utilities

Write Function

Write elements from a container with custom formatting.
template<typename T> // supported for vector, list and deque
void write(T &&ref, int n=-1, int start=0, string mid=" ", string end_l="\n") {
    if(n < 0) n = (int) ref.size();
    assert(0<=start && 0<=n && start+n<=(int)ref.size());
    auto end_it = next(begin(ref), start+n);
    for(auto it=next(begin(ref), start); it != end_it; it++)
        cout << *it << mid; 
    cout << end_l;
}
Parameters:
  • ref: Reference to container
  • n: Number of elements to write (default: all elements)
  • start: Starting index (default: 0)
  • mid: Separator between elements (default: space)
  • end_l: Line ending (default: newline)

Usage Examples

Write Entire Container

vector<int> arr = {1, 2, 3, 4, 5};
write(arr);
// Output: 1 2 3 4 5\n

Write Specific Range

vector<int> arr = {10, 20, 30, 40, 50, 60};
write(arr, 3, 1);  // Write 3 elements starting at index 1
// Output: 20 30 40\n

Custom Separator

vector<string> words = {"hello", "world", "test"};
write(words, -1, 0, ", ");
// Output: hello, world, test\n

vector<int> arr = {1, 2, 3};
write(arr, -1, 0, " -> ", "\n");
// Output: 1 -> 2 -> 3\n

No Newline at End

vector<int> arr = {1, 2, 3};
write(arr, -1, 0, " ", "");
// Output: 1 2 3 (no newline)

Write with Different Formatting

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

// Comma-separated
write(arr, -1, 0, ",", "\n");
// Output: 1,2,3,4,5\n

// Tab-separated
write(arr, -1, 0, "\t", "\n");
// Output: 1\t2\t3\t4\t5\n

// Each on new line
write(arr, -1, 0, "\n", "\n");
// Output:
// 1
// 2
// 3
// 4
// 5
Variadic template for printing multiple values with automatic spacing.
void print() { 
    cout << "\n"; 
}

template<class H, class... T> 
void print(const H& h, const T&... t) {
    cout << h;
    if(sizeof...(t)) cout << ' '; 
    print(t...);
}

Usage Examples

print();                    // Output: \n
print(42);                  // Output: 42\n
print("Hello", "World");    // Output: Hello World\n
int a = 10, b = 20;
print("Sum:", a + b);       // Output: Sum: 30\n

vector<int> v = {1, 2, 3};
print("Size:", v.size());   // Output: Size: 3\n

Complete Examples

Example 1: Array Sum

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

template<typename T>
void read(T &&ref, int n, int start=0) {
    assert(0<=start && 0<=n); 
    ref.resize(start+n);
    for(auto it=next(begin(ref), start); it != end(ref); it++)
        cin >> *it;
}

template<typename T>
void write(T &&ref, int n=-1, int start=0, string mid=" ", string end_l="\n") {
    if(n < 0) n = (int) ref.size();
    assert(0<=start && 0<=n && start+n<=(int)ref.size());
    auto end_it = next(begin(ref), start+n);
    for(auto it=next(begin(ref), start); it != end_it; it++)
        cout << *it << mid; 
    cout << end_l;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n;
    cin >> n;
    
    vector<int> arr;
    read(arr, n);
    
    long long sum = 0;
    for(int x : arr) sum += x;
    
    cout << sum << "\n";
    
    return 0;
}
Input:
5
1 2 3 4 5
Output:
15

Example 2: Matrix I/O

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n, m;
    cin >> n >> m;
    
    vector<vector<int>> matrix(n);
    for(int i = 0; i < n; i++) {
        read(matrix[i], m);
    }
    
    // Transpose
    vector<vector<int>> transposed(m, vector<int>(n));
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < m; j++) {
            transposed[j][i] = matrix[i][j];
        }
    }
    
    // Output transposed matrix
    for(int i = 0; i < m; i++) {
        write(transposed[i]);
    }
    
    return 0;
}
Input:
3 4
1 2 3 4
5 6 7 8
9 10 11 12
Output:
1 5 9
2 6 10
3 7 11
4 8 12

Example 3: Multiple Test Cases

void print() { cout << "\n"; }
template<class H, class... T> 
void print(const H& h, const T&... t) {
    cout << h;
    if(sizeof...(t)) cout << ' '; 
    print(t...);
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int t;
    cin >> t;
    
    while(t--) {
        int n;
        cin >> n;
        
        vector<int> arr;
        read(arr, n);
        
        int minVal = *min_element(arr.begin(), arr.end());
        int maxVal = *max_element(arr.begin(), arr.end());
        
        print("Min:", minVal, "Max:", maxVal);
    }
    
    return 0;
}

Example 4: 1-Indexed Array Processing

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n;
    cin >> n;
    
    vector<int> arr;
    read(arr, n, 1);  // 1-indexed
    
    // arr[0] is uninitialized/zero
    // arr[1..n] contains the input
    
    for(int i = 1; i <= n; i++) {
        arr[i] *= 2;  // Double each element
    }
    
    write(arr, n, 1);  // Write from index 1
    
    return 0;
}

I/O Optimization Tips

Basic Optimization

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    
    // Your code here
    
    return 0;
}
Always use ios_base::sync_with_stdio(false) and cin.tie(nullptr) for faster I/O.

Reading Multiple Values

// Instead of:
int a, b, c;
cin >> a >> b >> c;

// Use read for arrays:
vector<int> values;
read(values, 3);
int a = values[0], b = values[1], c = values[2];

Writing Without Extra Spaces

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

// Write without trailing space
for(int i = 0; i < arr.size(); i++) {
    if(i > 0) cout << " ";
    cout << arr[i];
}
cout << "\n";

// Or use write with custom formatting
write(arr, arr.size(), 0, " ", "\n");

Flush Control

// Avoid flushing unnecessarily
cout << x << "\n";        // Good (no flush)
cout << x << endl;        // Bad (flushes buffer)

// Manual flush when needed
cout << x << "\n" << flush;

Advanced Patterns

Reading Pairs

vector<pair<int, int>> pairs;
int n;
cin >> n;

for(int i = 0; i < n; i++) {
    int a, b;
    cin >> a >> b;
    pairs.push_back({a, b});
}

Reading Graph Edges

int n, m;  // nodes, edges
cin >> n >> m;

vector<vector<int>> adj(n + 1);

for(int i = 0; i < m; i++) {
    int u, v;
    cin >> u >> v;
    adj[u].push_back(v);
    adj[v].push_back(u);
}

Custom Input Format

// Read until EOF
vector<int> all_numbers;
int x;
while(cin >> x) {
    all_numbers.push_back(x);
}

// Read line by line
string line;
while(getline(cin, line)) {
    // Process line
}

Performance Comparison

MethodTime (1M integers)Notes
scanf/printfFastestC-style, format strings
cin/cout (optimized)Very fastWith sync_with_stdio(false)
cin/cout (default)SlowSynchronized with C I/O
read/write utilitiesVery fastBuilt on optimized cin/cout
For maximum speed with C++ I/O, use read/write with I/O optimizations enabled.

When to Use What

Use read when:

  • Reading arrays or containers of known size
  • Need automatic resizing
  • Want cleaner code for bulk input

Use write when:

  • Outputting entire containers
  • Need custom formatting
  • Want consistent spacing

Use print when:

  • Printing mixed types
  • Need automatic spacing
  • Quick debug output

Use standard cin/cout when:

  • Reading single values
  • Complex input parsing
  • Custom format requirements

Common Pitfalls

Don’t mix C and C++ I/O: If you use sync_with_stdio(false), don’t use scanf/printf.
Check array bounds: The read function uses assertions but not all judges enable them.
Flush when needed: Interactive problems require flushing after each query.

Build docs developers (and LLMs) love