櫻子奇怪の小愛好(Codeforces Round 970 (Div. 3)D)

土木牢盖發表於2024-11-27

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




相關文章