Enseñarte a dividir el árbol

Punto

• Mira una pregunta primero

• P3806 Dado un árbol con n puntos, pregunte si hay un par de puntos en el árbol con una distancia de k.
• N <= 10000

• ¡Cree que eres inteligente! n dfs veces!

• Pero no puedo hacerlo

Entonces veamos como hacerlo

• ¿Qué es el punto divide y vencerás?

• El punto divide y vencerás es una manera eficiente de lidiar con problemas en el árbol, con una excelente complejidad de tiempo y pensamiento inteligente.

• Primero introducimos el centro de gravedad del árbol

• El centro de gravedad del árbol también se llama centro de masa del árbol. Encuentre un punto donde el subárbol más grande tenga el menor número de nodos en todos los subárboles, entonces este punto es el centro de gravedad del árbol. Después de eliminar el centro de gravedad, los múltiples árboles generados están lo más equilibrados posible.

•¿Qué significa eso?

• Podemos deducir de aquí que el tamaño de cualquier subárbol enraizado en el centro de gravedad del árbol no excede n / 2

• ¿Cómo solicitarlo?

• Simplemente defina dfs directamente

• Mira el código

Inserte la descripción de la imagen aquí
• Solo tenemos que seguir buscando el centro de gravedad y usar estos centros para calcular la respuesta que queremos

• Pongamos un ejemplo

• Primero podemos encontrar un centro de gravedad y calcular la contribución de todos los caminos a través del centro de gravedad a la respuesta

• Por lo general, atraviesa el subárbol para resolver

• Esta pregunta pregunta si hay una ruta de longitud k, que es la longitud registrada hasta cada punto del subárbol con el centro de gravedad como punto de partida.

• Si puede usar un cubo, hágalo directamente; si no puede, use un mapam a p encuentra una longitud desde el centro de gravedad hastaxxEl punto de x es ver si la longitud desde el centro de gravedad esk - x kxk-x sub puntos dentro de los dos puntos no pueden enfocar la atención nuevamente al mismo hijo del árbol

• Se cuenta la contribución de la trayectoria a través de este centro de gravedad

• Luego, el centro de gravedad dividió el árbol original en varios subárboles.

• Divide y conquista para calcular la contribución del subárbol

• De manera similar, encuentre la contribución de las estadísticas del centro de gravedad del subárbol y divida y conquistará ...

• Porque podemos deducir de aquí que el tamaño de cualquier subárbol enraizado en el centro de gravedad del árbol no excede n / 2

• Cada vez que el tamaño del árbol no exceda la mitad del original, log 2 log_2l o g2Después de N veces, el tamaño del árbol se convertirá en 1, y cada vez que se atraviese todo el árbol como máximo O (N) O (N)O ( N ) , la complejidad esO (N log N) O (NlogN)O ( N L O G N ) de

Árbol punteado

• El árbol punteado se basa en dividir y conquistar, el árbol original se "convierte en estructura virtual".

• En el proceso de dividir y conquistar, almacenamos el centro de gravedad superior de cada centro de gravedad de división y conquista, que es la relación padre-hijo del árbol punteado.

• Obviamente, de acuerdo con el principio de dividir y conquistar puntos, la altura del árbol de la rama puntual es logn lognl o g n . De esta manera, podemos usar este árbol para ejecutar algo como "Desde el punto de consulta, siga saltandofa faLa violencia de f a , para resolver las múltiples consultas / modificaciones en algunos árboles.

Tome un árbol para simular la construcción de una rama.

Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
• Mira la pregunta

• P6329 proporciona un árbol con pesos de puntos y requiere procesamiento en línea.
• La suma de los pesos de puntos de los puntos cuya distancia entre 0 xk y el nodo x es menor o igual que k
• 1 xy El peso de los puntos del nodo x se convierte en y
1 ≤ n, m ≤ 1 0 5 1≤n, m≤10 ^ 51n ,metro1 05

• Construya un punto por árbol, cada punto mantiene un vector como un cubo y mantiene la suma del peso del punto de la distancia k desde el punto actual en el subárbol en el punto por árbol. Es decir, el subíndice del vector es k y el valor es la suma de los pesos. Cada vez que solicita un vector, dfs atraviesa el subárbol

• La respuesta al subárbol es encontrar la suma del prefijo del vector.

• De esta manera, para la consulta, solo necesita saltar a la rama del árbol cada vez, y luego calcular la distancia fa fa para cada fa en la rama del árbol.f ak - dios (hace, x) k-dis (hace, x)k-d i s ( f a ,La contribución de x ) está bien. (Fa faf axxxdis (hace, x) dis (hace, x)d i s ( f a ,x ) está tan lejos, por lo que el punto que puede contribuir está lejos defa faf ak - dios (hace, x) k-dis (hace, x)k-d i s ( f a ,x ) lejos)

• Pero hay otro problema, es decir, para la fa fa actualLos subárboles con f a como raíz están contando el siguientefa faCuando f a , se ponderará.

• Así que tenemos que mantener un balde, lo que significa xxx punto dentro del árbol molecular, hasta la rama de puntoxxLa distancia del padre de x eskkEl peso puntual de k . Dado que los pesos laterales son todos 1, esta operación será muy conveniente.

• Teniendo en cuenta que si hay una modificación , no es más que reemplazar el depósito con una matriz de árbol .

• Al construir un árbol, cada punto tiene como máximo logn lognl o g n antepasados, de modo que elregistro de registromás visitadol o g n veces

• Para este problema, debido a que se usa la matriz de árbol, hay un registro más

• Es hora de construir el árbol O (nlog 2 n) O (nlog ^ 2 n)O ( n l o g2 n)

• ¿Cómo modificarlo?

• Suponga que modificamos el punto como x

• Cada vez que la violencia salta, cada antepasado en el árbol fa

• Modificó la contribución de xa fa

• Por lo tanto, logn logn debe omitirse para cada modificaciónl o g n La contribución a la modificación delsubascedadorrequiereO (logn) O (logn)O ( l o g n )

• Tiempo de modificación O (log 2 n) O (log ^ 2 n)O ( l o g2 n)

• Luego, al resolver la respuesta, también salte logn lognl o g n segundo antepasado

• Cada vez que se encuentra la contribución en el subárbol se requiere O (logn) O (logn)O ( l o g n )

• El tiempo para resolver la respuesta O (log 2 n) O (log ^ 2 n)O ( l o g2 n)

Mira otra pregunta

P2056 [ZJOI2007] El escondite

Jiajia y Wind son una pareja amorosa y tienen muchos hijos. Un día, Jiajia, Wind y los niños decidieron jugar al escondite en casa. Su casa es muy grande y tiene una estructura extraña, que consta de N habitaciones y pasillos de dos vías N -1. La distribución de estos pasillos N -1 hace que dos habitaciones sean accesibles entre sí.

El juego es así, los niños se encargan de esconderse, Jiajia se encarga de encontrar, y Wind se encarga de manipular las luces en estas N casas. Al principio, no todas las luces estaban encendidas. Cada vez, los niños solo se esconderán en la habitación donde las luces no están encendidas, pero para aumentar la emoción, los niños pedirán encender la luz en una habitación determinada o apagar la luz en una habitación determinada. Para evaluar la complejidad de un determinado juego, Jiajia quiere saber la distancia entre los dos niños más lejanos posibles (es decir, la distancia entre las dos habitaciones más lejanas con las luces apagadas).

Definiremos cada operación de la siguiente forma:

-C (cambio) i cambia el estado de iluminación de la i- ésima habitación, si estaba encendida se apagará, si estaba apagada se encenderá.
-G (ame) Inicia un juego y consulta la distancia entre las dos habitaciones más alejadas con las luces apagadas.

Obviamente construye una rama de árbol

Cada vez que cambiamos una luz, afectará la información de una cadena en el árbol punteado. Salta directamente.

Considere mantener las respuestas, abrimos tres grandes pilas de raíces , una para mantener la cadena más larga en el subárbol, otra para mantener la cadena más larga hasta el nodo principal y otra para mantener todas las respuestas.

Mantenga un montón de todas las respuestas, preste atención a las actualizaciones en cualquier momento

Al contar las respuestas, cada subárbol solo necesita tomar el valor más grande y el siguiente valor más grande .

La complejidad general es O (nlog 2 n) O (nlog_2n)O ( n l o g2n ) , suficiente para pasar esta pregunta.

#include<bits/stdc++.h>
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(fast)
#define inf 1e9
#define N 100100
using namespace std;
inline char get_char(){
	static char buf[1000000],*p1,*p2;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int read(){
    int numm=0;
    char _;_=get_char();
    while(_<'0'||_>'9'){_=get_char();} 
    while(_>='0'&&_<='9'){numm=(numm<<3)+(numm<<1)+(_^48);_=get_char();   }
    return numm;
}
int n,f1[N],nxt1[N*2],data1[N*2],num,now,siz[N];
int f[N],nxt[N*2],data[N*2],dep[N];
int fa[N],dis[N];
bool vis[N],lt[N];
vector<int> disnow[N];
struct node{
	priority_queue<int> x,y;
	inline void push(int a){x.push(a);}
    inline void del(int a){y.push(a);}
    inline int top(){while(y.size()&&x.top()==y.top())x.pop(),y.pop();return x.top();}
    inline int size(){return x.size()-y.size();}
    inline void pop(){while(y.size()&&x.top()==y.top())x.pop(),y.pop();x.pop();}
    inline int sectop(){int a=top();pop();int b=top();push(a);return b;} 
	inline void clear(){while(x.size())x.pop();while(y.size())y.pop();}
}ans,far[N],ma[N];
inline void ans_push(node &x){
	if(x.size()>=2)ans.push(x.top()+x.sectop());
}
inline void ans_del(node &x){
	if(x.size()>=2)ans.del(x.top()+x.sectop());
}
void add(int x,int y){
	nxt1[++num]=f1[x];
	f1[x]=num;
	data1[num]=y;
}
void add2(int x,int y){
	nxt[++num]=f[x];
	f[x]=num;
	data[num]=y;
}
void find_rt(int x,int &root,int sum,int pp){
	siz[x]=1;
	int y,maxx=0;
	for(int i=f1[x];i;i=nxt1[i]){
		y=data1[i];
		if(y==pp||vis[y])continue;
		find_rt(y,root,sum,x);
		siz[x]+=siz[y];
		maxx=max(maxx,siz[y]);
	}
	maxx=max(siz[x],sum-siz[x]);
	if(maxx<now){
		now=maxx;root=x;
	}
}
void get_far(int s,int x,int y,int pp){
	far[0].push(y);
	disnow[x].push_back(y);
	siz[x]=1;
	int v;
	for(int i=f1[x];i;i=nxt1[i]){
		v=data1[i];
		if(v==pp||vis[v])continue;
		get_far(s,v,y+1,x);
		siz[x]+=siz[v];
	}
}
void build(int x,int pp){
	vis[x]=1;
	int y,root;
	for(int i=f1[x];i;i=nxt1[i]){
		y=data1[i];
		if(vis[y])continue;
		far[0].clear();
		get_far(pp,y,1,x);
		now=inf;
		find_rt(y,root,siz[y],-1);
		far[root]=far[0];fa[root]=x;dep[root]=dep[x]+1;
		add2(x,root);
		if(far[root].size())ma[x].push(far[root].top());
		build(root,x);
	}
	ma[x].push(0);
	ans_push(ma[x]); 
}

void work1(int x){
	int xx=x,pp,tmp=1;
	ans_del(ma[x]);
	ma[x].del(0);
	
	while(fa[xx]){
		pp=fa[xx];
		ans_del(ma[pp]);
		ma[pp].del(far[xx].top());
		xx=pp;
	}
	xx=x;
	ans_push(ma[x]);
	
	while(fa[xx]){
		pp=fa[xx];
		tmp=disnow[x][dep[pp]];
		far[xx].del(tmp);
		if(far[xx].size())
		ma[pp].push(far[xx].top());
		ans_push(ma[pp]);
		xx=pp;
	}
}

void work2(int x){
	int xx=x,pp,tmp=1;
	
	ans_del(ma[x]);
	while(fa[xx]){
		pp=fa[xx];
		ans_del(ma[pp]);
		if(far[xx].size())
		ma[pp].del(far[xx].top());
		xx=pp;
	}
	xx=x;
	ma[x].push(0);
	ans_push(ma[x]);
	while(fa[xx]){
		pp=fa[xx];
		tmp=disnow[x][dep[pp]];
		far[xx].push(tmp);
		ma[pp].push(far[xx].top());
		ans_push(ma[pp]);
		xx=pp;
	}
}

int main(){
//	freopen("test.txt","r",stdin);
	n=read();
	
	int a,b;
	for(int i=1;i<n;i++){
		a=read();b=read();
		add(a,b);add(b,a);
	}
	num=0;
	int root;
	now=inf;
	find_rt(1,root,n,-1);
	build(root,-1);
	int Q; char ss='0';
	Q=read();
	while(Q--){
		ss=get_char();
		while(ss!='G'&&ss!='C')ss=get_char();
//		cout<<ss<<' ';
		if(ss=='G'){
			if(ans.size()) printf("%d\n",ans.top());
			else printf("-1\n"); 
		}
		else{
			a=read();
//			cout<<a<<endl;
			if(!lt[a]){
				work1(a);
			}
			else work2(a);
			lt[a]^=1;
		}
	}
} 

En un principio, comencé a escribir blogs con frecuencia en
julio . Oye, es el 20 de julio, ¿por qué soy un plato así?

Supongo que te gusta

Origin blog.csdn.net/RA100FDM/article/details/107460101
Recomendado
Clasificación