Lexicographically largest string from allowed swaps
Your code is quite good for a beginning, but there's still much room for improvement. Your code main flaw is that it is difficult to read. There are also some performance issues, but they are a lot easier to correct.
N.B: I'll stay close to your algorithm, although you could probably find a better one in a graph library (see for instance https://en.wikipedia.org/wiki/Connected_component_(graph_theory)#algorithms)
Performance
You must pick your types more carefully. Don't choose a type that allocates memory when you can use one that doesn't. For instance, don't represent a pair of indices by a std::vector: a pair will always have two elements, there is no need to ever grow it. So choose a std::pair&lt;int, int&gt; instead: it is lighter, quicker, and reflects your intent more clearly. In the same way, don't use std::string to represent 1 character: your stringpool can as well be of type std::vector&lt;std::string&gt;.
You must also be more careful while passing objects around. Don't pass large objects by value unless you need both to copy and modify them. For instance, the signature: std::string swapLexOrder(std::string str, std::vector&lt;std::vector&lt;int&gt;&gt; pairs) is only partially correct. You will indeed modify str, and you want the user to keep his original string untouched, so passing by value is a good call. But pairs is read-only in your code, so pass it by const reference.
Expressiveness
Your code is one big function containing a lot of nested loops. As a result,it's very hard to understand, let alone optimize. There is two ways to fix it: the first is to better comment on your algorithm (for instance, a minimum would be: first, we merge all pairs of indices that are connected together; then we extract the corresponding characters from the input string, sort them in decreasing order and put them back); the second, is to make your code express your intent clearly.
The most important rule, which also is one of the hardest to obey, is to choose meaningful names. newset doesn't mean much, neither does p. pairpool should not contain set of more than two elements.
Another way to write more expressive code is to avoid &quot;raw loops&quot;. Use named algorithms instead. For instance, I rewrote the first part of your algorithm as a combination of a partition discriminating sets containing one element of the considered pair and an accumulation which merges them:
std::string swapLexOrder(std::string str, const std::vector&lt;std::pair&lt;int, int&gt;&gt;&amp; pairs)
{
    if(pairs.size() == 0) return str;
    std::vector&lt;std::set&lt;int&gt;&gt; index_permutations; //pairpool : contains sets of interchangeable indices
    
    for(auto pair : pairs)
    {   
        // [matches, end) &lt;- sets containing either one of the pair's elements   
        auto matches = std::partition(index_permutations.begin(), index_permutations.end(), 
                                      [&amp;pair](const auto&amp; permutation_set) {
            return std::none_of(permutation_set.begin(), permutation_set.end(), [&amp;pair](auto index) {
                return index == pair.first || index == pair.second;
            });
        });
        
        if (matches == index_permutations.end()) index_permutations.push_back({pair.first, pair.second});
        else { // merge matches
            *matches = std::accumulate(matches, index_permutations.end(),
                                       std::set&lt;int&gt;{pair.first, pair.second},
                                       [](auto&amp;&amp; init, auto&amp;&amp; permutation) {
                init.insert(permutation.begin(), permutation.end());
                return init;
            });
            index_permutations.erase(std::next(matches), index_permutations.end());
        }
    }
// ...

Here's a link to the partially rewritten code if you want to experiment with it: https://wandbox.org/permlink/6Wij6Y4NuooMlW6C