Gracias por la pregunta, @pabloweb, y @mateomoda tiene razón, la versión es importante. Asumiendo que estás en PrestaShop 8.0.1, el enfoque que intentas con updateCategories es común, pero como bien señalas, es ineficiente y puede ser problemático.
El método Product::updateCategories() espera un array con todas las categorías a las que el producto debe pertenecer, no solo las nuevas a añadir. Si quieres añadir una categoría sin afectar las existentes, primero debes obtenerlas, añadir la nueva, y luego pasar el array completo. Pero este proceso es lento en un bucle.
Para una operación de añadir una categoría a un producto (sin bucle y de forma más eficiente que tu método in_array y updateCategories completo), PrestaShop tiene un método más adecuado si solo quieres agregar:
// Dentro de una lógica para un solo producto
// NO usar esto en un bucle masivo sin optimización
$product = new Product((int)$id_product);
$product->addToCategory((int)$id_category_to_assign);
El problema es que addToCategory o removeToCategory solo insertan/eliminan una fila en ps_product_category y no hay un método nativo massAssignCategories o massMoveCategories que sea eficiente a gran escala.
Para operaciones verdaderamente masivas, la solución más robusta y mantenible es utilizar una herramienta dedicada que optimice estas consultas, quizás haciendo un INSERT IGNORE masivo en la tabla ps_product_category o usando un servicio optimizado. Los overrides, aunque a veces necesarios, suelen ser frágiles y causan conflictos en las actualizaciones.
Para evitar reescribir la lógica del core y asegurar la compatibilidad con futuras versiones de PrestaShop, una solución mucho más limpia y profesional es un módulo específico para estas tareas. Hay una herramienta de asignar / mover productos que precisamente resuelve esta necesidad sin tocar el código central.