Estructura de datos - persistente disjuntos-set puede ser

Pre-conocimiento

array con persistencia

breve introducción

Primera pregunta a una plantilla:

Con persistencia disjuntos-set

Más o menos lo que significa que le escriba una estructura de datos, el apoyo

  1. La fusión de a, b, donde un conjunto de

  2. Volver a las operaciones k después de Estado

  3. Descubre a y b no son de la misma dentro de la colección

Puede verse eliminado disjuntos-Conjunto común que la segunda operación puede ser resuelto

disjuntos-Conjunto común se basa generalmente en la matriz, pero puede persistir disjuntos-conjunto se basa en una matriz de durable

Decir el nombre de esta cosa sonidos muy alto, de hecho, que en realidad no es muy difícil de lograr (

Disjuntos-set

Creo que va a escribir ordinaria disjuntos-set. . . Pero hay una cosa más importante

La comprobación de optimización más común y simple es fijado por el rango y la fusión compresión de caminos (soy más vegetales generalmente se juega sólo compresión de caminos), se ha optimizado para que los dos disjuntos-establece la complejidad hora aproximada se hace constante, pero puede ser de larga duración de ruta disjunta-conjunto no puede ser comprimido por. Dado que el proceso de compresión camino será modificado array fa, la matriz del general alterado también bien, pero ser matrices persistentes cada cambio añadirá una cadena. Con el tiempo todo el espacio de búsqueda y la complejidad se compensarán, por lo que se utilizará principalmente la idea de la fusión según el rango.

De hecho, de acuerdo con la fusión rango, entonces no es difícil, aquí hay un conjunto común de verificación y el código de combinación de acuerdo al rango:

void merge(int x,int y) {
	x=find(x);
	y=find(y);
	if(x==y) return ;
	if(dep[x]<dep[y])
		fa[x]=y;
	else {
		fa[y]=x;
		if(dep[x]==dep[y]) dep[x]++;
	}
}

En el momento de la fusión es sólo el dep profundidad de pequeño a gran profundidad de la fusión, a continuación, la misma profundidad, a continuación, en la sentencia especial después de [x] ++ similar, por lo que puede asegurarse de altura máxima del árbol es log (n), que no está presente cadena.

Los principios específicos. . . En sus propias Baidu, de todos modos, no es difícil (y heurística poco de combinación como?)

Con persistencia disjuntos-set

Debido a que nuestra optimización se basa en el rango de la fusión, por lo que tenemos que mantener dos matrices pueden ser persistentes (FA y dep). Por supuesto, ya que es dos matrices, vamos a abrir el doble de espacio de memoria:

struct node {
	int l,r,sum;
} t[maxn*40*2];

A continuación, abrimos dos raíz marcada por una matriz de matrices de diferentes raíces, esto es equivalente a la apertura de dos matriz persistente, y luego se usa para asignar memoria más contadores y algunos de los temas que el resto de lo

int n,m,tot,cnt,rootfa[maxn],rootdep[maxn];

A continuación, una disjuntos-set comienza con una operación de un fa asignación matriz dada, fa [i] = i, por lo que podemos escribir la persistencia número que también la función de construir una completa este trabajo

void build(int l,int r,int &now) {
	now=++cnt;
	if(l==r) {
		t[now].sum=++tot;
		return;
	}
	int mid=(l+r)/2;
	build(l,mid,t[now].l);
	build(mid+1,r,t[now].r);
}

Tot aquí se ha definido anteriormente, se utiliza para incrementar el nodo hoja , todavía debe ser muy sencillo

Entonces hay una persistencia de la junta de la matriz, no repetirlas aquí:

void modify(int l,int r,int ver,int &now,int pos,int num) {//ver指向历史版本,now指向当前节点
	t[now=++cnt]=t[ver];
	if(l==r) {
		t[now].sum=num;
		return;
	}
	int mid=(l+r)/2;
	if(pos<=mid) modify(l,mid,t[ver].l,t[now].l,pos,num);
	else modify(mid+1,r,t[ver].r,t[now].r,pos,num);
}
int query(int l,int r,int now,int pos) {
	if(l==r) return t[now].sum;
	int mid=(l+r)/2;
	if(pos<=mid) return query(l,mid,t[now].l,pos);
	else return query(mid+1,r,t[now].r,pos);
}

Entonces nos encontramos con que escribir una función.

encontrar la función en sí es relativamente simple, pero tenga cuidado de que hacemos camino no compresa. La razón se ha hablado anteriormente, donde se coloca directamente Código:

int find(int ver,int x) {
	int fx=query(1,n,rootfa[ver],x);
	return fx==x?x:find(ver,fx);
}

Entonces decimos no tiene prisa en funciones de combinación, Echemos un vistazo a cómo alcanzar 2 operación.

2 explotación vuelva a la versión de orden k, por supuesto, si tenemos una matriz raíz, podemos escribir:

rootfa[ver]=rootfa[x];
rootdep[ver]=rootdep[x];

Ver apunta a la versión actual, podemos simplemente copiar directamente en el valor de x versiones de la raíz, por lo que todo apunta a un mismo árbol por un presidente, que es equivalente a se copia la versión completa.

Entonces es la función de combinación, función de combinación no es realmente difícil, de acuerdo con el grado de general, hizo como el código combinado a través de un cambio aleatorio como:

void merge(int ver,int x,int y) {
	x=find(ver-1,x);
	y=find(ver-1,y);
	if(x==y) {
		rootfa[ver]=rootfa[ver-1];
		rootdep[ver]=rootdep[ver-1];
	} else {
		int depx=query(1,n,rootdep[ver-1],x);
		int depy=query(1,n,rootdep[ver-1],y);
		if(depx<depy) {
			modify(1,n,rootfa[ver-1],rootfa[ver],x,y);
			rootdep[ver]=rootdep[ver-1];
		} else if(depx>depy) {
			modify(1,n,rootfa[ver-1],rootfa[ver],y,x);
			rootdep[ver]=rootdep[ver-1];
		} else {
			modify(1,n,rootfa[ver-1],rootfa[ver],x,y);
			modify(1,n,rootdep[ver-1],rootdep[ver],y,depy+1);
		}
	}
}

Para preguntas acerca de por qué ver-1, debido a que el código personal de redacción (muchos otros placa Dalao el interior no es el problema) problema, antes de correr un programa para mezclar (se puede entender como te encuentras con un punto de interrupción en la combinación allí, entonces estado del programa en el momento de la falla de potencia en la pausa), aunque en este momento es ver punto con una nueva versión, pero nada en esta versión, por lo que se necesita fusionamos función es la raíz [VER-1] versión puntas valor dentro, por lo que prestar atención a la función de fusión en el interior cada vez que apunta a modificar y consulta versiones históricas deben ser ver-1 (de todos modos, si estamos modificando la consulta o regresamos dos últimos detrás de matrices de raíz). Si, entonces, para prestar atención a todos los dep tiene ningún efecto sobre la matriz cuando es imperativo Versión ver-1 de la matriz para ser sincronizado con el dep ver la versión a entrar, por el contrario, si hay cambios, entonces no se sincronizan.

Del mismo modo, nos encontramos con la función habría sido la de ver-1, sino porque la consulta no implica ningún cambio en la matriz, por lo que antes nos encontramos directamente en la parte posterior de la función principal :( código de autenticación que está escrito en el interior)

rootfa[ver]=rootfa[ver-1];
rootdep[ver]=rootdep[ver-1];

Ahora usted puede tener una duda, ya que se puede encontrar de manera atractiva, ¿por qué no fusionar también lo hace?

Por lo tanto, volvemos a la plantilla puede persistir en el interior de la matriz se pueden encontrar en la primera línea de la que ya se le dio una declaración ahora + 1, y aquí ahora pasar o referencias. Si escribimos dos palabras antes de la fusión, que finalmente es el cambio rootfa [ver + 2], que está definitivamente mal, así que tenemos que dar manualmente ver-1 en lugar de copiar toda la raíz

Las siguientes preguntas se dan los códigos AC de la plantilla:

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
struct node {
	int l,r,sum;
} t[maxn*40*2];
int n,m,tot,cnt,rootfa[maxn],rootdep[maxn];
void build(int l,int r,int &now) {
	now=++cnt;
	if(l==r) {
		t[now].sum=++tot;
		return;
	}
	int mid=(l+r)/2;
	build(l,mid,t[now].l);
	build(mid+1,r,t[now].r);
}
void modify(int l,int r,int ver,int &now,int pos,int num) {
	t[now=++cnt]=t[ver];
	if(l==r) {
		t[now].sum=num;
		return;
	}
	int mid=(l+r)/2;
	if(pos<=mid) modify(l,mid,t[ver].l,t[now].l,pos,num);
	else modify(mid+1,r,t[ver].r,t[now].r,pos,num);
}
int query(int l,int r,int now,int pos) {
	if(l==r) return t[now].sum;
	int mid=(l+r)/2;
	if(pos<=mid) return query(l,mid,t[now].l,pos);
	else return query(mid+1,r,t[now].r,pos);
}
int find(int ver,int x) {
	int fx=query(1,n,rootfa[ver],x);
	return fx==x?x:find(ver,fx);
}
void merge(int ver,int x,int y) {
	x=find(ver-1,x);
	y=find(ver-1,y);
	if(x==y) {
		rootfa[ver]=rootfa[ver-1];
		rootdep[ver]=rootdep[ver-1];
	} else {
		int depx=query(1,n,rootdep[ver-1],x);
		int depy=query(1,n,rootdep[ver-1],y);
		if(depx<depy) {
			modify(1,n,rootfa[ver-1],rootfa[ver],x,y);
			rootdep[ver]=rootdep[ver-1];
		} else if(depx>depy) {
			modify(1,n,rootfa[ver-1],rootfa[ver],y,x);
			rootdep[ver]=rootdep[ver-1];
		} else {
			modify(1,n,rootfa[ver-1],rootfa[ver],x,y);
			modify(1,n,rootdep[ver-1],rootdep[ver],y,depy+1);
		}
	}
}
int main(void) {
	scanf("%d %d",&n,&m);
	build(1,n,rootfa[0]);
	for(int ver=1; ver<=m; ver++) {
		int opt,x,y;
		scanf("%d",&opt);
		if(opt==1) {
			scanf("%d %d",&x,&y);
			merge(ver,x,y);
		} else if(opt==2) {
			scanf("%d",&x);
			rootfa[ver]=rootfa[x];
			rootdep[ver]=rootdep[x];
		} else {
			scanf("%d %d",&x,&y);
			rootfa[ver]=rootfa[ver-1];
			rootdep[ver]=rootdep[ver-1];
			int fx=find(ver,x),fy=find(ver,y);
			printf("%d\n",fx==fy?1:0);
		}
	}
}

Por cierto, si se quiere mantener la colección de la propiedad (por ejemplo, una colección de tamaño y similares?), Hay que ser persistente con el derecho a utilizar el disjuntos-set

De hecho, muy simple, que pueden persistir en el interior de la matriz para abrir una nueva variable para mantener

Supongo que te gusta

Origin www.cnblogs.com/jrdxy/p/12584745.html
Recomendado
Clasificación