2020 Niuke Winter Holiday Algorithm Basic Training Camp 1 F maki and tree 【También verifique】

Descripción del título

Un día, Maki consiguió un árbol. El llamado árbol es un gráfico conectado no dirigido sin auto-bucles, aristas dobles y bucles.
Este árbol tiene n vértices y n-1 aristas. Cada vértice está teñido de blanco o negro.
¿Maki quiere saber cuántos puntos diferentes se toman en sus senderos simples con un solo punto negro?
Nota:
① Las dos rutas simples en el árbol se refieren a la ruta más corta que conecta los dos puntos.
Methods Los métodos de <p, q> y <q, p> se consideran iguales.

Ingrese la descripción 

Un entero positivo n en la primera línea. Representa el número de vértices. (1 \ leq n \ leq 100000)
La segunda línea es una cadena que consta solo de los caracteres 'B' y 'W'. El i-ésimo carácter es B para el i-ésimo punto es negro, y W para el i-ésimo punto es blanco.
Las siguientes n-1 líneas, cada línea de dos enteros positivos x, y, representa que x e y están conectadas por un borde.(1 \ leq x, y \ leq n)

Descripción de salida

Un entero positivo que indica el número de caminos que solo pasan a través de un punto negro.

Entrada de ejemplo 

3
WBW
1 2
2 3

Salida de muestra 

3

Análisis:

 Hay dos casos para una ruta que pasa solo un punto negro:

1. El punto negro está al final del camino.

2. El punto negro está en el medio del camino.

En ambos casos, en realidad se requiere mantener un grupo de puntos blancos, es decir, un grupo de puntos blancos que pueden llegar directamente entre sí sin pasar a través de los puntos negros.

Para el primer caso, la ruta involucrada en cada punto negro es la suma del número de puntos blancos en todos los grupos de puntos blancos conectados al punto   \ small \ sum_ {i = 1} ^ {n} x_ {i};

Para el segundo caso, la ruta involucrada en cada punto negro es: en todos los grupos de puntos blancos conectados al punto, el número de puntos blancos en cualquiera de los dos grupos se multiplica y luego se suma \ small \ sum_ {i = 1} ^ {n} \ sum_ {j = i + 1} ^ {n} x_ {i} * x_ {j} ∑ i = 1 n xi

Use y verifique los grupos que mantienen puntos blancos y mantenga el número de puntos blancos en cada grupo.

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

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <map>
using namespace std;
typedef long long ll;
const int maxn = 100000 + 5;

int n;

int fa[maxn],sum[maxn];
char str[maxn];
vector<int> v[maxn];//记录与黑色点相连的白色点
vector<int> black;//记录黑色点
map<int,int> mp;

int find(int x){
	if(fa[x]==x)  return x;
	int root=find(fa[x]);
	sum[x]+=sum[fa[x]];	//路径压缩过程中,组内白点个数的更新 
	return fa[x]=root;
}

void merge(int a,int b){//两组合并
	int ffa=find(a),ffb=find(b);
    if(ffa==ffb)  return;
	fa[ffb]=ffa;
	sum[ffa]+=sum[ffb];
} 

void init(){
	for(int i=0;i<=n;i++){
		fa[i]=i;
        sum[i]=1;//初始化每个白点自己成为一组
	}
}


int main() {
    scanf("%d",&n);
    scanf("%s",str+1);
    for(int i=1;i<=n;i++){
        if(str[i]=='B'){
            mp[i]=1;
            black.push_back(i);
        }
    }
    init();
    int x,y;
    for(int i=1;i<n;i++){
        scanf("%d%d",&x,&y);
        if(mp[x]&&!mp[y]){
            v[x].push_back(y);
        }
        else if(!mp[x]&&mp[y]){
            v[y].push_back(x);
        }
        else if(!mp[x]&&!mp[y]){//两个白点相连,合并两组
            merge(x,y);
        }
    }
    ll ans=0;
    for(int i=0;i<black.size();i++){//对每个黑点进行计算
        ll cnt=0;//记录所有与该黑点相连组的白点总数,简化第二种情况下的内层循环
        for(int j=0;j<v[black[i]].size();j++){
            int ff1=find(v[black[i]][j]);
            ans=ans+sum[ff1];
            cnt+=sum[ff1];
        }
        for(int j=0;j<v[black[i]].size();j++){
            int ff1=find(v[black[i]][j]);
            cnt-=sum[ff1];
            ans=ans+cnt*sum[ff1];
        }
    }
    printf("%lld\n",ans);
    return 0;
}

 

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

Supongo que te gusta

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