Embora o @Marc tenha fornecido (o que eu acho que seja) uma excelente análise, algumas pessoas podem preferir considerar as coisas de um ângulo um pouco diferente.
Uma é considerar uma maneira ligeiramente diferente de realizar uma realocação. Em vez de copiar todos os elementos do armazenamento antigo para o novo armazenamento imediatamente, considere copiar apenas um elemento por vez - ou seja, cada vez que você faz um push_back, ele adiciona o novo elemento ao novo espaço e copia exatamente um existente elemento do espaço antigo para o novo espaço. Assumindo um fator de crescimento 2, é bastante óbvio que, quando o novo espaço estiver cheio, teríamos terminado de copiar todos os elementos do espaço antigo para o novo espaço, e cada push_back teria exatamente o tempo constante. Nesse ponto, descartávamos o espaço antigo, alocávamos um novo bloco de memória com ganho duas vezes maior e repetíamos o processo.
Muito claramente, podemos continuar indefinidamente (ou desde que haja memória disponível) e cada push_back envolveria a adição de um novo elemento e a cópia de um elemento antigo.
Uma implementação típica ainda tem exatamente o mesmo número de cópias - mas, em vez de fazer as cópias uma por vez, copia todos os elementos existentes de uma só vez. Por um lado, você está certo: isso significa que, se você observar invocações individuais de push_back, algumas delas serão substancialmente mais lentas que outras. Se observarmos uma média de longo prazo, no entanto, a quantidade de cópias feitas por chamada de push_back permanece constante, independentemente do tamanho do vetor.
Embora seja irrelevante para a complexidade computacional, acho que vale a pena apontar por que é vantajoso fazer as coisas como elas fazem, em vez de copiar um elemento por push_back, para que o tempo por push_back permaneça constante. Há pelo menos três razões a considerar.
O primeiro é simplesmente a disponibilidade de memória. A memória antiga pode ser liberada para outros usos somente após a conclusão da cópia. Se você apenas copiasse um item por vez, o antigo bloco de memória permaneceria alocado por muito mais tempo. Na verdade, você teria um bloco antigo e um novo bloco alocados essencialmente o tempo todo. Se você optar por um fator de crescimento menor que dois (o que geralmente deseja), precisará de ainda mais memória alocada o tempo todo.
Segundo, se você apenas copiasse um elemento antigo de cada vez, a indexação na matriz seria um pouco mais complicada - cada operação de indexação precisaria descobrir se o elemento no índice fornecido estava atualmente no antigo bloco de memória ou no novo. Isso não é terrivelmente complexo de forma alguma, mas para uma operação elementar como a indexação em uma matriz, quase qualquer desaceleração pode ser significativa.
Terceiro, copiando tudo de uma vez, você aproveita muito melhor o cache. Copiando de uma só vez, você pode esperar que a origem e o destino estejam no cache na maioria dos casos, para que o custo de uma falha de cache seja amortizado pelo número de elementos que caberão em uma linha de cache. Se você copiar um elemento de cada vez, poderá facilmente ter uma falta de cache para cada elemento que copiar. Isso muda apenas o fator constante, não a complexidade, mas ainda pode ser bastante significativo - para uma máquina típica, você pode esperar facilmente um fator de 10 a 20.
Provavelmente também vale a pena considerar a outra direção por um momento: se você estivesse projetando um sistema com requisitos em tempo real, seria bom copiar apenas um elemento de cada vez, em vez de todos de uma vez. Embora a velocidade geral possa (ou não) ser menor, você ainda terá um limite superior rígido no tempo necessário para uma única execução de push_back - presumindo que você tenha um alocador em tempo real (embora, é claro, muitos em tempo real os sistemas simplesmente proíbem a alocação dinâmica de memória, pelo menos em partes com requisitos em tempo real).