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