Tu as raison il faut utiliser un pointeur (ou une référence). Ce qui se passe dans ton cas c'est qu'une copie du tableau est créée à l'entrée de ta fonction, c'est cette copie qui est modifiée dans la fonction, et détruite à la sortie. Bilan des courses : l'original n'est pas modifié.
Pour utiliser un pointeur ta fonction devra avoir un prototype du genre :
void contamine(int x, int y, std::vector<std::vector<int>> *populus);
Puis à l'intérieur de ta fonction il faudra utiliser la valeur pointée au lieu du pointeur lui-même : (*populus)[i], ou populus->size() par exemple.
Pour la solution de la référence le prototype devient :
void contamine(int x, int y, std::vector<std::vector<int>>& populus);
Et le code de ta fonction ne change pas.
Partager