(并查集)2020牛客寒假算法基础集训营1F.maki和tree

2020牛客寒假算法基础集训营1F.maki和tree

思路:

刚开始想用带权并查集做,权值想设为x到y点经过的黑点数,但是后来发现这样写不了,因为这与x的颜色,y的颜色,和中间经过点的颜色都有关,并不是简单的加减可得的。
后来看了题解。
是用并查集求出白连通块,然后存在两种情况符合要求,一种是一个断电为黑色,另一种是,中间经过的点为黑色。

代码:

#include<bits/stdc++.h>
#define pii pair<int,int>
#define ll long long
#define cl(x,y) memset(x,y,sizeof(x))
#define ct cerr<<"Time elapsed:"<<1.0*clock()/CLOCKS_PER_SEC<<"s.\n";
const int N=1e5+10;
const int mod=1e7+9;
const int maxn=0x3f3f3f3f;
const int minn=0xc0c0c0c0;
const int inf=99999999;
using namespace std;
char s[N];
ll head[N]={0},len=0,fa[N],size[N]={0};
struct edge
{
	ll next,to;
}maze[4*N];
void add(int u,int v)
{
	maze[++len]={head[u],v};
	head[u]=len;
}
int find(int x)
{
	if(fa[x]!=x)
		fa[x]=find(fa[x]);
	return fa[x];
}
void merge(int x,int y)
{
	int t1=find(x),t2=find(y);
	if(t1!=t2)
	{
		fa[t1]=t2;
		size[t2]+=size[t1];
	}
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int n,i,j;
	cin>>n>>s+1;
	for(i=1;i<=n;i++)
	{
		fa[i]=i;
		if(s[i]=='W')
			size[i]=1;
	}
	for(i=1;i<n;i++)
	{
		int x,y;
		cin>>x>>y;
		add(x,y);
		add(y,x);
		if(s[x]=='W' && s[y]=='W')
			merge(x,y);
	}
	ll sum=0;
	for(i=1;i<=n;i++)
	{
		if(s[i]=='B')
		{
			ll tot=0;
			for(j=head[i];j;j=maze[j].next)
				tot+=size[find(maze[j].to)];
			sum+=tot;
			for(j=head[i];j;j=maze[j].next)
			{
				tot-=size[find(maze[j].to)];
				sum+=tot*size[find(maze[j].to)];
			}
		}
	}
	cout<<sum<<endl;
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章