链接:https://ac.nowcoder.com/acm/contest/3002/F
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

有一天,maki拿到了一颗树。所谓树,即没有自环、重边和回路的无向连通图。
这个树有 个顶点, 条边。每个顶点被染成了白色或者黑色。
maki想知道,取两个不同的点,它们的简单路径上有且仅有一个黑色点的取法有多少?
注:
①树上两点简单路径指连接两点的最短路。
的取法视为同一种。

 
 
 

输入描述:

第一行一个正整数n。代表顶点数量。

第二行是一个仅由字符'B'和'W'组成的字符串。第 i个字符是B代表第 i 个点是黑色,W代表第 i个点是白色。
接下来的n-1行,每行两个正整数 x , y,代表 x 点和 y点有一条边相连 

输出描述:

一个正整数,表示只经过一个黑色点的路径数量。
示例1

输入

复制

3
WBW
1 2
2 3

输出

复制

3

说明

树表示如下:
其中只有2号是黑色点。
<1,2>、<2,3>、<1,3>三种取法都只经过一个黑色点。
 
思路:
   对于可以连边的白色节点,用并查集把节点合并,并且在合并时更新连通块大小。
   对于一条含有黑色节点的路径,我们易知:路径数 = 黑色节点相邻的 白连通块内点的size * 该点相连的白连通块点的size···
   
   所以只需要先求出白连通块的大小,然后对于黑点,只需要计算出黑点相邻白连通块加上其的后继连通块即可。
   后继白连通块大小求法:
   

   关于_find中为什么是sum += sz[r2]的问题,因为建的是无向图,不保证此时的fa[r1]一定是与fa[r2]相等的

  

 #include <bits/stdc++.h>
#define dbg(x) cout << #x << "=" << x << endl using namespace std;
typedef long long LL;
const int maxn = 1e6 + ; int n;
LL ans;
int fa[maxn];
int a[maxn];
int head[maxn];
char c[maxn];
int cnt = ;
LL sz[maxn];
LL num[maxn];
int _count = ; //vector <int> g[maxn]; struct Edge {
int to,nxt;
}edge[maxn]; void BuildGraph(int u, int v) {
edge[cnt].to = v;
edge[cnt].nxt = head[u];
head[u] = cnt++; edge[cnt].to = u;
edge[cnt].nxt = head[v];
head[v] = cnt++;
} void init()
{
memset(head, -, sizeof(head));
for(int i = ; i <= n; i++) {
fa[i] = i;
sz[i] = ;
}
} namespace _buff {
const size_t BUFF = << ;
char ibuf[BUFF], *ib = ibuf, *ie = ibuf;
char getc() {
if (ib == ie) {
ib = ibuf;
ie = ibuf + fread(ibuf, , BUFF, stdin);
}
return ib == ie ? - : *ib++;
}
} int read() {
using namespace _buff;
int ret = ;
bool pos = true;
char c = getc();
for (; (c < '' || c > '') && c != '-'; c = getc()) {
assert(~c);
}
if (c == '-') {
pos = false;
c = getc();
}
for (; c >= '' && c <= ''; c = getc()) {
ret = (ret << ) + (ret << ) + (c ^ );
}
return pos ? ret : -ret;
} int fid(int x)
{
int r = x;
while(fa[r] != r) {
r = fa[r];
}
int i,j;///路径压缩
i = x;
while(fa[i] != r) {
j = fa[i];
fa[i] = r;
i = j;
}
return r;
} void join(int r1,int r2)///合并
{
int fidroot1 = fid(r1), fidroot2 = fid(r2);
int root = min(fidroot1, fidroot2);
sz[root] = sz[fidroot1] + sz[fidroot2];
if(fidroot1 != fidroot2) {
fa[fidroot2] = root;
fa[fidroot1] = root;
}
} LL _find(int x) {
//dbg(x);
LL sum = ;
for(int i = head[x]; ~i; i = edge[i].nxt) {
int v = edge[i].to;
if(a[v]) {
//num[v] = 0;
continue;
}
int r1 = fid(x), r2 = fid(v);
sum += sz[r2];
num[++_count] = sz[r2];
}
return sum;
} int main()
{
scanf("%d\n",&n);
init();
ans = ;
scanf("%s",c);
for(int i = ; i < n; ++i) {
if(c[i] == 'W') {
a[i+] = ;
}
else {
a[i+] = ;
}
}
for(int i = ; i < n; ++i) {
int x, y;
scanf("%d %d",&x, &y);
BuildGraph(x,y);
if(!a[x] && !a[y]) {
join(x,y);
}
}
for(int i = ; i <= n; ++i) {
if(a[i] == ) continue;
_count = ;
memset(num, , sizeof(num));
ans += _find(i);
for(int j = ; j <= _count; ++j) {
for(int k = j+; k <= _count; ++k) {
ans += num[j] * num[k];
}
}
} printf("%lld\n",ans);
}
 

2020牛客寒假算法基础集训营1 F-maki和tree的更多相关文章

  1. 2020牛客寒假算法基础集训营2 J题可以回顾回顾

    2020牛客寒假算法基础集训营2 A.做游戏 这是个签到题. #include <cstdio> #include <cstdlib> #include <cstring ...

  2. 2020牛客寒假算法基础集训营1 J题可以回顾回顾

    2020牛客寒假算法基础集训营1 这套题整体来说还是很简单的. A.honoka和格点三角形 这个题目不是很难,不过要考虑周全,面积是1,那么底边的长度可以是1也可以是2, 注意底边1和2会有重复的, ...

  3. 2020牛客寒假算法基础集训营4-F树上博弈

    链接:https://ac.nowcoder.com/acm/contest/3005/F来源:牛客网 题目描述 现有一个 n 个点,n-1条边组成的树,其中 1 号点为根节点. 牛牛和牛妹在树上玩游 ...

  4. 2020牛客寒假算法基础集训营4-I 匹配星星【贪心】

    链接:https://ac.nowcoder.com/acm/contest/3005/I来源:牛客网 示例1 输入 复制 2 1 1 0 2 2 1 2 1 1 0 2 2 1 输出 复制 1 1 ...

  5. 牛客寒假算法基础集训营4 F Applese 的大奖

    链接:https://ac.nowcoder.com/acm/contest/330/H来源:牛客网 Applese 和它的小伙伴参加了一个促销的抽奖活动,活动的规则如下:有一个随机数生成器,能等概率 ...

  6. 牛客寒假算法基础集训营4 F Applese 的QQ群

    链接:https://ac.nowcoder.com/acm/contest/330/F来源:牛客网 Applese 有一个QQ群.在这个群中,大家互相请教问题.如 b 向 a 请教过问题,就把 a ...

  7. 2020牛客寒假算法基础集训营5 G街机争霸

    题目描述 哎,又是银首,要是你这个签到题少WA一发就金了 牛牛战队的队员打完比赛以后又到了日常甩锅的时间.他们心情悲伤,吃完晚饭以后,大家相约到一个街机厅去solo.牛牛和牛能进入了一个迷宫,这个迷宫 ...

  8. 2020牛客寒假算法基础集训营4 D:子段异或

    D : 子段异或 考察点 : 位运算,前缀和,异或的性质和应用 坑点 : 0 - L 的异或值是 0 的话也是一个区间 相同的值可能有多个,那么这时候区间就会有多个(x * (x + 1) / 2) ...

  9. 2020牛客寒假算法基础集训营6 I.导航系统 (最小生成树)

    https://ac.nowcoder.com/acm/contest/3007/I 题中给定的图必定是一棵树 容易发现,如果将输入的N(N-1)个距离看做N(N-1)条无向边的话,那么如果数据合法, ...

随机推荐

  1. C——简单计算器(HDU1237)

    题目: 读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值.  Input测试输入包含若干测试用例,每个测试用例占一行,每行不超过200个字符,整数和运算符之间用一个空格分隔 ...

  2. redis中key键操作

    keys */查看所有的key remoteSelf:1>select 0 "OK" remoteSelf:0>keys * 1) "SUBCRIBEMAP& ...

  3. rpm 程序包管理介绍

    API:application program interface ABI:application binary interface linux系统的ABI文件是ELF格式的 windows系统的AB ...

  4. github无法访问的解决实践

    无废话版: ----------------------------- 1.复制下面内容,添加到hosts文件里(C:\Windows\System32\drivers\etc)不能修改的话,则把文件 ...

  5. gcd手写代码及STL中的使用方法

    一.手写代码 inline int gcd(int x,int y){ if(y==0) return x; else return(gcd(y,x%y)); } 二.STL中的使用方法 注:在STL ...

  6. Dijkstra算法2

    // 再来一手精髓的Dijkstra // 复杂度O( E*log(V) ) #include <cstdio> #include <iostream> #include &l ...

  7. Openshift部署流程介绍

    背景 Openshift是一个开源容器云平台,是一个基于主流的容器技术Docker和Kubernetes构建的云平台.Openshift底层以Docker作为容器引擎驱动,以Kubernetes 作为 ...

  8. C#常见基础算法

    namespace 面试常见算法 { class Program { static void Main(string[] args) { ); Console.WriteLine(n1); Test2 ...

  9. BZOJ #2989. 数列 [树套树]

    考虑转化问题模型,这个没必要可持久化,直接加点就可以了,还不用删点 每次的问题是求 曼哈顿距离,变成切比雪夫距离然后求解 然后我们考虑将这玩意旋转 45度, 然后原坐标的 \((x,y)\) 会变成 ...

  10. composer封装dd函数

    1.安装composer,本人用的phpstudy,打开php扩展php_openssl 2.切换到www目录下 cmd 命令 composer 第一个就是我们要找的 3.运行composer req ...