(並查集)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;
}

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