Decompose two vectors
For something easy to read and maintain I'd use set_difference and set_intersection which would work well on sorted ranges with no duplicates:
std::set_intersection(a.begin(), a.end(), b.begin(), b.end(), std::back_inserter(both));

only_a.reserve(a.size() - both.size());
std::set_difference(a.begin(), a.end(), b.begin(), b.end(), std::back_inserter(only_a));

only_b.reserve(b.size() - both.size());
std::set_difference(b.begin(), b.end(), a.begin(), a.end(), std::back_inserter(only_b));

...but that requires that you iterate over the ranges three times, and I think you are looking for something more efficient.
First, I would not start by copying a and b into only_a and only_b respectively. Instead, take inspiration from the example implementations for the standard functions I linked to above and create your own similar algorithm. This requires that Ts can be compared with operator&lt;:
#include &lt;algorithm&gt;
#include &lt;iterator&gt;

template &lt;class T&gt;
void decompose(std::vector&lt;T&gt;&amp; a,
               std::vector&lt;T&gt;&amp; b,
               std::vector&lt;T&gt;&amp; only_a,
               std::vector&lt;T&gt;&amp; only_b,
               std::vector&lt;T&gt;&amp; both)
{
    // Sort the input or require the input to be sorted like some algorithms do
    // If you'd like the input to be unchanged, make a and b const and make
    // copies of them instead and sort those copies.
    std::sort(a.begin(), a.end());
    std::sort(b.begin(), b.end());

    // clear destination vectors or skip this if you want to append instead
    only_a.clear();
    only_b.clear();

    // the actual algorithm - loop for as long as both vectors have elements

    auto ait = a.begin();
    auto bit = b.begin();

    while(ait != a.end() &amp;&amp; bit != b.end()) {
        if(*ait &lt; *bit) {
            only_a.push_back(*ait++);  // can only be in a
        } else if(*bit &lt; *ait) {
            only_b.push_back(*bit++);  // can only be in b
        } else {
            both.push_back(*ait++);    // must be in both
            ++bit;
        }
    }

    // Add the remaining elements if not both ait and bit have reached their end()
    if(ait != a.end()) std::copy(ait, a.end(), std::back_inserter(only_a));
    else if(bit != b.end()) std::copy(bit, b.end(), std::back_inserter(only_b));
}

Or make it even more generic and let it work with iterators only and add the possibility for the user to supply a Compare functor. This do require the ranges to be sorted in the same order as they would be if the Compare functor was used with std::sort on the ranges. The default Compare functor is here std::less&lt;&gt; that, if not specialized for the type involved, uses operator&lt; to compare the elements.
#include &lt;functional&gt; // less
#include &lt;iterator&gt;   // iterator_traits

template &lt;
    class First1, class Last1, class First2, class Last2,
    class OnlyAinserter, class OnlyBinserter, class BothInserter,
    class Comp = std::less&lt;typename std::iterator_traits&lt;First1&gt;::value_type&gt;
    // class Comp = std::less&lt;&gt; // &lt;- is sufficient in C++14 and forward
&gt;
void decompose(First1 ait, Last1 aend, First2 bit, Last2 bend,
               OnlyAinserter onlyait, OnlyBinserter onlybit, BothInserter bothit,
               Comp comp = Comp{})
{
    // loop for as long as both vectors have elements
    while(ait != aend &amp;&amp; bit != bend) {
        if(comp(*ait, *bit)) {
            *onlyait++ = *ait++;  // can only be in a
        } else if(comp(*bit, *ait)) {
            *onlybit++ = *bit++;  // can only be in b
        } else {
            *bothit++ = *ait++;   // must be in both
            ++bit;
        }
    }

    // Add the remaining elements if not both ait and bit have reached aend/bend
    if(ait != aend) std::copy(ait, aend, onlyait);
    else if(bit != bend) std::copy(bit, bend, onlybit);
}

Which can then be called like this using the default Compare functor:
decompose(a.begin(), a.end(), b.begin(), b.end(), 
    std::back_inserter(only_a), std::back_inserter(only_b), std::back_inserter(both));

Or like below, supplying a Compare functor. In this example the ranges are required to be sorted in descending order:
decompose(a.begin(), a.end(), b.begin(), b.end(), 
    std::back_inserter(only_a), std::back_inserter(only_b), std::back_inserter(both),
    [](auto&amp; A, auto&amp; B) { return A &gt; B; } // std::greater&lt;&gt;
);