2019 Bullock Summer Multi-School Training Camp (Noveno) E Todos los hombres son hermanos

Descripción del título

Amy le pregunta al Sr. B el problema E. Ayude al Sr. B a resolver el siguiente problema.

Hay n personas que no se conocen al principio.

Hay m turnos. En cada turno, 2 de ellos se harán amigos entre sí.

La relación de amistad es mutua y transitiva.

Si A es amigo de B, entonces B también es amigo de A.

Por ejemplo, si A es amigo de B, B es amigo de C, entonces A y C son amigos.

Al principio y después de cada turno, calcule la cantidad de formas de seleccionar cuatro personas, de modo que dos de estos cuatro no sean amigos.

Ingrese la descripción 

La primera línea contiene dos enteros, ny m (n <= 100000, m <= 200000), que son el número de personas y el número de turnos.

En las siguientes líneas m, la línea i-ésima contiene dos enteros x e y (1 <= x <= n, 1 <= y <= n, x ≠ y), lo que significa la persona x-ésima y la y- La persona hace amigos en el turno i.

La persona x-ésima y la persona-y-ésima pueden hacer amigos en varios turnos.

Descripción de salida 

Salida m + 1 líneas, cada línea contiene un número entero, que es el número de cuádruples.

Salida al principio y después de cada turno, por lo que hay m + 1 líneas.

Ejemplo de entrada 1 

6 6
1 2
3 4
4 5
3 5
3 6
2 4

Ejemplo de salida 1 

15
9
4
0
0
0
0

Ejemplo de entrada 2 

100000 0

Salida de muestra 2 

4166416671249975000

Explicación 

No uses int.

La idea principal:

Hay n personas, realizan m operaciones. Cada operación hace amigos a dos personas, y la relación entre los amigos se puede transferir, es decir, cuando las dos personas se hacen amigos, todos los que son amigos de las dos personas se hacen amigos.

Después de realizar cada operación, seleccione la cantidad de programas diferentes en los que cuatro personas no son amigos.

Análisis:

A partir de las operaciones en el título y la transitividad de la relación, es concebible utilizar y verificar el mantenimiento del conjunto, mientras se mantiene el número de elementos en cada conjunto.

En el estado inicial, el número de soluciones es  C_n ^ 4 , consideramos el número restado en cada operación.

El esquema para cada resta es seleccionar uno de los dos conjuntos actuales y, además, seleccionar uno de los dos conjuntos de los otros conjuntos. Suponga que el número de elementos en los dos conjuntos combinados es a y b, entonces el número de resta cada vez = a * b * (seleccione dos elementos de otros conjuntos, y los dos elementos no están en el mismo conjunto de planes).

Para encontrar la cantidad de soluciones en las que se seleccionan dos elementos de otras colecciones y los dos elementos no están en la misma colección, primero puede encontrar la cantidad de alternativas y luego restar la cantidad de soluciones de la misma colección.

Por lo tanto, podemos mantener un valor tmp durante cada operación tmp = \ sum_ {i = 1} ^ {k} C_ {tamaño [i]} ^ 2(el tamaño [i] es el número de elementos en cada conjunto) y registrar el número de opciones para seleccionar dos elementos en el mismo conjunto en el estado actual.

Vea el código para una explicación específica.

#include <bits/stdc++.h>

using namespace std;

typedef unsigned long long ll;

const ll maxn=100005;

ll fa[maxn],size[maxn];

//并查集的Get操作 
ll get(ll x){
	if(fa[x]==x)  return x;
	return fa[x]=get(fa[x]);
}

//并查集的Merge操作
void merge(ll x,ll y){
	ll fx=get(x),fy=get(y); 
	fa[fy]=fx;
	size[fx]=size[fx]+size[fy];
}

//计算每个集合中选择两个元素的方案数 
ll getCi2(ll num){
	if(num<2)  return 0;
	else  return num*(num-1)/2;
}

int main(){
	ll n,m;
	scanf("%lld%lld",&n,&m);
	ll x,y;
	//初始化 
	for(ll i=1;i<=n;i++){
		fa[i]=i;
		size[i]=1;
	}
	//n<4要单独判断 
	if(n<4){
		for(ll i=1;i<=(m+1);i++){
			printf("0\n"); 
		}
		return 0;
	}
	ll ans=n*(n-1)/2*(n-2)/3*(n-3)/4;//这里要注意不能按下行的方式写,否则中间结果会溢出unsigned long long 
//	ll ans=(n*(n-1)*(n-2)*(n-3))/(24);
	printf("%lld\n",ans); 
	ll tmp=0;//维护的tmp值 
	for(ll i=1;i<=m;i++){
		scanf("%lld%lld",&x,&y);
		ll fx=get(x),fy=get(y);
		if(fx==fy){//若两个人已经是朋友,不做操作 
			printf("%lld\n",ans);
			continue;
		}
		//减去当前两个集合下的方案数 
		tmp-=getCi2(size[fx]);
		tmp-=getCi2(size[fy]);
		ans-=size[fx]*size[fy]*((n-size[fx]-size[fy])*(n-size[fx]-size[fy]-1)/2-tmp);
		printf("%lld\n",ans);
		tmp+=getCi2(size[fx]+size[fy]);//更新tmp值 
		merge(x,y);//合并两个集合 
	}
	return 0;
} 

 

30 artículos originales publicados · ganó 5 · 900 visitas

Supongo que te gusta

Origin blog.csdn.net/qq_42840665/article/details/99682386
Recomendado
Clasificación