Está en la página 1de 3

Tarea 5 - Mo, DSU, rollback Ángel Manuel González López

Chef and Graph Queries

El problema se resuelve utilizando el algoritmo Mo, junto con la estructura Disjoint Set Union (DSU) para
optimizar las consultas en un grafo.

La estructura DSU se usó para administrar conjuntos disjuntos en el grafo lo que nos permitió unir conjuntos
y determinar si dos elementos pertenecen al mismo conjunto.
struct DisjointSet {
int tam ,* padre ,* cantHijos , numCompConx ;

void reinicio ( void ) ;


int representante ( int nodo ) ;
e s t a n R el a c i o n a d o s ( int unNodo , int otroNodo ) ;
unir ( int x , int y ) ;
record ( void ) ;
rollBack ( void ) ;
}

Es un DSU clásico con unos metodos extras reinicio(), record() y rollback() que nos permite deshacer
cambios desde que querramos empezar a grabar y también deshacer todo.

El algoritmo Mo se utiliza para procesar consultas en bloques de tamaño conveniente (la raiz de cantidad de
aristas totales) para recorrer las preguntas eficientemente y de este modo pasar en tiempo.
struct MoAlgortim {
struct Query {
int L , R , id , bloque ;
};
int Q ;
vector < Query > Queries ;
int * respuestas ;
void A gr eg ar P re gu nt a ( int ll , int rr , int dd ) ;
void O r d e n a r P r e g u n t a s ( void ) ;
Conte starQue ry ( int id , int answer ) ;
void I m p r i m i r R e s p u e s t a s ( void ) ;
}

Como en actividades pasadas el orden que usamos es:


bool operator < ( Query \& otra ) {
return make_pair ( L / Tam_Bloque , R ) < make_pair ( otra . L / Tam_Bloque , otra . R ) ;
}

La idea para resolver el problema es contar el número de componentes conexas en un grafo después de agregar
unos aristas en particular.

Para cada caso de prueba (que se realiza por separado), se leen los datos, y las preguntas para utiliza el
algoritmo Mo y ası́ procesar las consultas en orden establecido anteriormente
for ( int i =0; i < Q ; i ++ ) {
cin >> l >> r ;
MO . A g re ga rP r eg un ta (l ,r , i ) ;
}
MO . O r d en a r P re g u n t a s () ;
Tarea 5 - Mo, DSU, rollback Página 2/3

Posteriormente para cada pregunta L new, R new (añadir todas las aristas desde L a R) se divide en dos
casos
Cambio de bloque (o primera pregunta).

Segunda operación dentro del mismo bloque.

Primer caso: Cada vez que estamos en un nuevo bloque tenemos que reiniciar nuestra estructura de datos,
luego tomamos todas las aristas que estén desde el final de nuestro bloque hasta R new.
ElGrafo . reinicio () ;
for ( int i = fin ; i <= R_new ; i ++ ) {
ElGrafo . unir ( u [ i ] , v [ i ]) ;
}

R new

··· bloque Actual ···
| {z }| {z }| {z }| {z }| {z }
√ √ √ √ √
N N N N N

Figura 1: derecha

Luego para la parte de la izquierda activamos ElGrafo.record() y rellenamos todos los datos entre L new
y el final del bloque ( o bien R new si este fuese menor que el final del bloque).
ElGrafo . record () ;
for ( int i = L_new ; i <= min ( fin -1 , R_new ) ; i ++ ) {
ElGrafo . unir ( u [ i ] , v [ i ]) ;
}

L new

··· bloque Actual ···
| {z }| {z }| {z }| {z }| {z }
√ √ √ √ √
N N N N N

Figura 2: izquierda

Luego guardamos la respuesta a esta pregunta, es decir guardamos la cantidad de componentes conexas del
grafo, y posteriormente llamamos al método rollback() ya que la parte izquierda no nos será de utilidad.
MO . Conte starQue ry ( id , ElGrafo . numCompConx ) ;
ElGrafo . rollBack () ;

··· bloque Actual ···


| {z }| {z }| {z }| {z }| {z }
√ √ √ √ √
N N N N N

Figura 3: rollback();
Tarea 5 - Mo, DSU, rollback Página 3/3

Segundo caso: Si es una pregunta que pertenece al mismo bloque que la pregunta anterior, entonces el
valor de R new aumento respecto al anterior R old, ası́ que podemos rellenar desde R old hasta R new.
for ( int i = max ( fin -1 , R_old ) ; i <= R_new ; i ++ ) {
ElGrafo . unir ( u [ i ] , v [ i ]) ;
}

R old R new
↓ ↓
··· bloque Actual ···
| {z }| {z }| {z }| {z }| {z }
√ √ √ √ √
N N N N N

Figura 4: Derecha

Respecto a la parte izquierda, hacemos exactamente lo mismo que en el caso anterior, la diferenciación de
casos solo nos sirvió para la derecha.

L new R new
↓ ↓
··· bloque Actual ···
| {z }| {z }| {z }| {z }| {z }
√ √ √ √ √
N N N N N

Figura 5: Izquierda

De igual forma, guardamos la respuesta y posteriormente llamamos al método rollback();

··· bloque Actual ···


| {z }| {z }| {z }| {z }| {z }
√ √ √ √ √
N N N N N

Figura 6: rollback();

Al finalizar todas las preguntas ya que resultado de cada una quedó almacenado en el arreglo respuestas
solo queda imprimir el resultado al final.

También podría gustarte