import std.algorithm;
import std.concurrency;
import std.container;
import std.conv;
import std.functional;
import std.math;
import std.meta;
import std.random;
import std.range;
import std.stdio;
import std.string;
import std.traits;
import std.typecons;


auto solve(int N, int M, int[] L, int[] R) {
    auto cards = SegmentTree!int(N);

    foreach (l, r; zip(L, R))
        cards[l - 1 .. r] += 1;
    
    return cards.count!(c => c.map!"a.value".sum == M);
}


void main() {
    auto input = stdin.byLine.map!split.joiner;

    int N;
    N = input.front.to!int;
    input.popFront;

    int M;
    M = input.front.to!int;
    input.popFront;

    int[] L = new int[](cast(size_t) (M));
    int[] R = new int[](cast(size_t) (M));
    foreach (i; 0 .. cast(size_t) (M)) {
        L[i] = input.front.to!int;
        input.popFront;
        R[i] = input.front.to!int;
        input.popFront;
    }

    static if (is(ReturnType!solve == void))
        solve(N, M, L, R);
    else
        solve(N, M, L, R).writeln;
}



struct SegmentTree(T) {
private:
    size_t leaves_length;
    size_t completed_leaves_length;
    T[] data;

    size_t frontLeafIndex;
    size_t backLeafIndex;

public:
    this(size_t leaves_length) {
        this.leaves_length = leaves_length;
        completed_leaves_length = highestOneBit(leaves_length) * 2;
        data.length = completed_leaves_length * 2;

        frontLeafIndex = 0;
        backLeafIndex = leaves_length;
    }

    @property SegmentNode!T front()
    in {
        assert(!empty, "Attempted to get the front leaf of an empty SegmentTree range");
    }
    body {
        size_t nodeindex = getNodeIndexFromLeafIndex(frontLeafIndex);
        return createNode(nodeindex);
    }

    @property SegmentNode!T front(T value)
    in {
        assert(!empty, "Attempted to set the front leaf of an empty SegmentTree range");
    }
    body {
        size_t nodeindex = getNodeIndexFromLeafIndex(frontLeafIndex);
        data[nodeindex] = value;
        return createNode(nodeindex);
    }

    @property SegmentNode!T back()
    in {
        assert(!empty, "Attempted to get the back leaf of an empty SegmentTree range");
    }
    body {
        size_t nodeindex = getNodeIndexFromLeafIndex(backLeafIndex - 1);
        return createNode(nodeindex);
    }

    @property SegmentNode!T back(T value)
    in {
        assert(!empty, "Attempted to set the back leaf of an empty SegmentTree range");
    }
    body {
        size_t nodeindex = getNodeIndexFromLeafIndex(backLeafIndex - 1);
        data[nodeindex] = value;
        return createNode(nodeindex);
    }

    void popFront()
    in {
        assert(!empty, "Attempted to remove the front leaf of an empty SegmentTree range");
    }
    body {
        frontLeafIndex++;
    }

    void popBack()
    in {
        assert(!empty, "Attempted to remove the back leaf of an empty SegmentTree range");
    }
    body {
        backLeafIndex--;
    }

    @property typeof(this) save() {
        return this;
    }

    @property size_t length() {
        return backLeafIndex - frontLeafIndex;
    }

    @property bool empty() {
        return frontLeafIndex == backLeafIndex;
    }

    // a[i]
    ref auto opIndex(size_t leaf_index)
    in {
        assert(0 <= leaf_index && leaf_index < leaves_length, "Get access violation");
    }
    body {
        size_t nodeindex = getNodeIndexFromLeafIndex(leaf_index);
        return createNode(nodeindex);
    }

    // a[i .. j]
    auto opIndex(size_t[2] range) {
        return new std.concurrency.Generator!(SegmentNode!T)({
            auto l = range[0] + completed_leaves_length;
            auto r = range[1] + completed_leaves_length;
            while (l < r) {
                if (r & 1)
                    yield(createNode(--r));
                if (l & 1)
                    yield(createNode(l++));
                l >>= 1;
                r >>= 1;
            }
        });
    }

    // a[i] = x
    SegmentNode!T opIndexAssign(T value, size_t leaf_index)
    in {
        assert(0 <= leaf_index && leaf_index < leaves_length, "Set access violation");
    }
    body {
        size_t nodeindex = getNodeIndexFromLeafIndex(leaf_index);
        data[nodeindex] = value;
        return createNode(nodeindex);
    }

    // a[i .. j] = x
    auto opIndexAssign(T value, size_t[2] range) {
        auto l = range[0] + completed_leaves_length;
        auto r = range[1] + completed_leaves_length;
        size_t i;
        while (l < r) {
            if (r & 1)
                data[--r] = value;
            if (l & 1)
                data[l++] = value;
            l >>= 1;
            r >>= 1;
        }

        return this[range[0] .. range[1]];
    }

    // a[i] op= x
    SegmentNode!T opIndexOpAssign(string op)(T value, size_t index)
    in {
        assert(0 <= leaf_index && leaf_index < leaves_length, "Compond assignment access violation");
    }
    body {
        size_t nodeindex = getNodeIndexFromLeafIndex(leaf_index);
        mixin("data[nodeindex] %s= value;".format(op));
        return createNode(nodeindex);
    }

    // a[i .. j] op= x
    // auto opSliceOpAssign(string op)(T value, size_t range_l, size_t range_r) {
    //     auto l = range_l + completed_leaves_length;
    //     auto r = range_r + completed_leaves_length;
    //     size_t i;
    //     while (l < r) {
    //         if (r & 1)
    //             mixin("data[--r] %s= value;".format(op));
    //         if (l & 1)
    //             mixin("data[l++] %s= value;".format(op));
    //         l >>= 1;
    //         r >>= 1;
    //     }

    //     return this[range_l .. range_r];
    // }

    // a[i .. j] op= x
    auto opIndexOpAssign(string op)(T value, size_t[2] range) {
        auto l = range[0] + completed_leaves_length;
        auto r = range[1] + completed_leaves_length;
        size_t i;
        while (l < r) {
            if (r & 1)
                mixin("data[--r] %s= value;".format(op));
            if (l & 1)
                mixin("data[l++] %s= value;".format(op));
            l >>= 1;
            r >>= 1;
        }

        return this[range[0] .. range[1]];
    }


    // $
    size_t opDollar(size_t dim : 0)() {
        return length;
    }

    // i .. j
    size_t[2] opSlice(size_t dim : 0)(size_t i, size_t j) {
        return [i, j];
    }

    @property SegmentNode!T root() {
        return createNode(1);
    }

private:
    size_t getNodeIndexFromLeafIndex(size_t leaf_index) {
        return completed_leaves_length + leaf_index;
    }

    SegmentNode!T createNode(size_t index) {
        return SegmentNode!T(this, index);
    }

    struct SegmentNode(T) {
    private:
        SegmentTree!T tree;
        size_t index;
        bool _isOutOfTree;

    public:
        this(SegmentTree!T tree) {
            index = size_t.max;  // to avoid zero division
            this.tree = tree;
            _isOutOfTree = true;
        }

        this(SegmentTree!T tree, size_t index) {
            this.tree = tree;
            this.index = index;
            _isOutOfTree = index <= 0 || tree.data.length <= index;
        }

        @property typeof(this) left() {
            if (isLeaf || _isOutOfTree)
                return typeof(this)(tree);
            return typeof(this)(tree, index * 2);
        }

        @property typeof(this) right() {
            immutable childIndex = index * 2;
            immutable highestOneBitC = highestOneBit(childIndex);
            immutable childWidth = tree.completed_leaves_length / highestOneBitC;
            immutable childL = (childIndex - highestOneBitC) * childWidth + childWidth + 1;
            if (childL > tree.leaves_length || isLeaf || _isOutOfTree)
                return typeof(this)(tree);

            return typeof(this)(tree, index * 2 + 1);
        }

        @property typeof(this) parent() {
            if (_isOutOfTree)
                return typeof(this)(tree);
            return typeof(this)(tree, index / 2);
        }
    
        @property ref T value()
        in {
            assert(!_isOutOfTree);
        }
        body {
            return tree.data[index];
        }

        @property bool isLeaf() {
            return tree.completed_leaves_length <= index
                && index < tree.completed_leaves_length + tree.leaves_length && !_isOutOfTree;
        }

        @property bool isRoot() {
            return index == 1;
        }

        @property bool isOutOfTree() {
            return _isOutOfTree;
        }

        @property size_t width() {
            return tree.completed_leaves_length / highestOneBit(index);
        }

        @property size_t[2] segment() {
            auto l = (index - highestOneBit(index)) * width;
            return [l, l + width + 1];
        }

        @property typeof(this) front() {
            return this;
        }

        void popFront() {
            index /= 2;
        }

        @property bool empty() {
            return parent.isOutOfTree;
        }
    }
}

pure size_t highestOneBit(size_t n) {
    size_t k = 1;
    size_t highest;
    while (true) {
        if (k == 0)
            return highest;
        if ((k & n) != 0)
            highest = k;
        k <<= 1;
    }
}
