2020 Niuke Winter Holiday Algorithm Basic Training Camp 1 F maki and tree 【Also check】

Title description

One day, Maki got a tree. The so-called tree is an undirected connected graph without self-loops, double edges and loops.
This tree has n vertices and n-1 edges. Each vertex is dyed white or black.
Maki wants to know how many different points are taken on their simple paths with only one black point?
Note:
① The two simple paths on the tree refer to the shortest path connecting the two points.
② The methods of <p, q> and <q, p> are regarded as the same.

Enter description 

A positive integer n in the first line. Represents the number of vertices. (1 \ leq n \ leq 100000)
The second line is a string consisting only of the characters 'B' and 'W'. The i-th character is B for the i-th point is black, and W for the i-th point is white.
The next n-1 lines, each line of two positive integers x, y, represents that x and y are connected by an edge.(1\leq x,y\leq n)

Output description

A positive integer indicating the number of paths that only pass through a black dot.

Example input 

3
WBW
1 2
2 3

Sample output 

3

analysis:

 There are two cases for a path that passes only one black dot:

1. The black dot is at the end of the path.

2. The black dot is in the middle of the path.

In both cases, it is actually required to maintain a group of white dots, that is, a group of white dots that can directly reach each other without passing through the black dots.

For the first case, the path involved in each black point is the sum of the number of white points in all white point groups connected to the point   \small \sum_{i = 1}^{n}x_{i};

For the second case, the path involved in each black point is: in all the white point groups connected to the point, the number of white points in any two groups is multiplied and then summed \small \sum_{i = 1}^{n}\sum_{j = i + 1}^{n}x_{i} * x_{j}∑ i=1 n ​ x i

Use and check the groups that maintain white dots, and maintain the number of white dots in each group.

See the code for specific explanation.

#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;
}

 

Published 30 original articles · won 5 · 900 views

Guess you like

Origin blog.csdn.net/qq_42840665/article/details/104210347