樱子奇怪の小爱好(Codeforces Round 970 (Div. 3)D)
D. Sakurako's Hobby
对于某个排列 \(p\) \(^{\text{∗}}\) 如果可以通过赋值 \(i=p_i\) 一定次数使 \(i\) 等于 \(j\) ,则樱子称整数 \(j\) 可以从整数 \(i\) 到达
如果是 \(p=[3,5,6,1,2,4]\) ,那么,举例来说, \(4\) 可以从 \(1\) 到达,因为: \(i=1\) \(\rightarrow\) \(i=p_1=3\) \(\rightarrow\) \(i=p_3=6\) \(\rightarrow\) \(i=p_6=4\) .现在是 \(i=4\) ,所以 \(4\) 可以从 \(1\) 到达
排列中的每个数字都被染成黑色或白色
樱子将函数 \(F(i)\) 定义为从 \(i\) 可以得到的黑色整数的个数
樱子对每个 \(1\le i\le n\) 的 \(F(i)\) 都很感兴趣,但计算所有值变得非常困难,因此她请你作为她的好朋友来计算这个值
\(^{\text{∗}}\) 长度为 \(n\) 的排列是由 \(n\) 个不同的整数组成的数组,这些整数从 \(1\) 到 \(n\) 按任意顺序排列。例如, \([2,3,1,5,4]\) 是一个排列,但 \([1,2,2]\) 不是一个排列(数字 \(2\) 在数组中出现了两次), \([1,3,4]\) 也不是一个排列( \(n=3\) ,但数组中包含 \(4\) )
INPUT
第一行包含一个整数 \(t\) ( \(1\le t\le 10^4\) ) - 测试用例数
每个测试用例的第一行包含一个整数 \(n\) ( \(1\le n\le 2\cdot 10^5\) ) - 数组中的元素个数
每个测试用例的第二行包含 \(n\) 个整数 \(p_1, p_2, \dots, p_n\) ( \(1\le p_i\le n\) ) - 排列元素
每个测试用例的第三行包含一个长度为 \(n\) 的字符串 \(s\) ,由 "0 "和 "1 "组成。如果 \(s_i=0\) ,则数字 \(p_i\) 被涂成黑色;如果 \(s_i=1\) ,则数字 \(p_i\) 被涂成白色
保证所有测试用例中 \(n\) 的总和不超过 \(2\cdot 10^5\)
OUTPUT
对于每个测试用例,输出 \(n\) 个整数 \(F(1), F(2), \dots, F(n)\)
Example
Input
5
1
1
0
5
1 2 4 5 3
10101
5
5 4 1 3 2
10011
6
3 5 6 1 2 4
010000
6
1 2 3 4 5 6
100110
Output
1
0 1 1 1 1
2 2 2 2 2
4 1 4 4 1 4
0 1 1 0 0 1
[!TIP]
歌词大意:哼~ 哎呀呀,给了个长度是n的排列数组p还有长度也是n的颜色字符串s啦,真是的 ~ ❤要人家去算从每个位置能到达的所有位置里黑色数字的数量呢,哼!那个黑色数字就是字符串s里面的字符'0'表示的啦,真麻烦呀,不过杂鱼大哥哥不要认输呢,杂鱼大哥哥快点好好算一算啦,嘻嘻 ~ 杂鱼~ ❤❤❤
好像没用到动态规划的说❤❤❤,想上传那种图
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int f[N], g[N], fumo[N],p[N], t, n;//p[i]表示在排列中第 i 个位置上的值(从位置 i 可以到达的下一个位置)
char s[N];
// 查找根节点❤❤❤
int find(int x) {
if (f[x]!= x) {
f[x] = find(f[x]);
}
return f[x];
}
// 合并两个集合❤❤❤
void baka(int x, int y) {
int findX = find(x);
int findY = find(y);
if (findX!= findY) {
if (g[findX] > g[findY]) {
f[findY] = findX;
fumo[findX] += fumo[findY];
} else {
f[findX] = findY;
fumo[findY] += fumo[findX];
}
}
}
int main() {
scanf("%d", &t);
while (t--) {
scanf("%d", &n );
//排列数组❤❤❤
for (int i = 0; i < n; i++) {
scanf("%d", &p[i]);
p[i]--; //转换为0索引❤❤❤
}
scanf("%s", s);
// 初始化并查集❤❤❤
for (int i = 0; i < n; i++) {
f[i] = i;
g[i] = 0;
fumo[i] = 0;
}
// 初始化黑色数字计数❤❤❤
for (int i = 0; i < n; i++) {
if (s[i] == '0') {
fumo[find(i)]++;
}
}
//构建并查集❤❤❤
for (int i = 0; i < n; i++) {
baka(i, p[i]);//合并当前节点和排列数组中对应的节点❤❤❤
}
for (int i = 0; i < n; i++) {
printf("%d ", fumo[find(i)]);//啊~出来了~~~❤❤❤❤❤❤❤
}
printf("\n");
}
return 0;
}





浙公网安备 33010602011771号