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