#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define pii pair<int, int>
#define deb(n) cout << #n << "=" << n << " "
#define debug(n) cout << #n << "=" << n << endl
#define div() cout << "_______________" << endl
const int N = 2e5 + 10, mod = 998244353;
int n, k;
int A[N], dp[N][21], inC[N], distoC[N], pf[N], pfC[N], S[N];
vector<int> v[N], u[N];
vector<pii> G[N];
int tt[N], low[N], timestamp;
stack<int> s;
int ste[N];
int id[N], scc_cnt, dout[N], sz[N];
vector<int> LT[N];
void tarjan(int pre) {
tt[pre] = low[pre] = ++timestamp;
s.push(pre), ste[pre] = 1;
for (auto& to : v[pre]) {
if (!tt[to]) {
tarjan(to);
low[pre] = min(low[pre], low[to]);
}
else if (ste[to]) low[pre] = min(low[pre], tt[to]);
}
if (tt[pre] == low[pre]) {
int ver;
scc_cnt++;
do {
ver = s.top(); s.pop();
ste[ver] = 0;
id[ver] = scc_cnt;
LT[scc_cnt].push_back(ver);
sz[scc_cnt]++;
} while (ver != pre);
}
}
int getpos(int pre, int x) { // 计算pre开始走x步终点
int cnt = 0;
while (x) {
if (x & 1) pre = dp[pre][cnt];
cnt++;
x /= 2;
}
return pre;
}
void dfs(int pre) { // 树上前缀和
if (ste[pre]) return;
ste[pre] = 1;
for (auto& to : u[pre]) {
if (inC[to]) continue;
dfs(to);
pf[pre] += pf[to];
}
}
void solveC(int pre) { // 环上前缀和
ste[pre]++;
if (ste[pre] == 3) return; // 转两圈
if (ste[pre] == 1) for (auto& it : G[pre]) S[pre] += it.first, S[it.second] -= it.first; // 差分
for (auto& to : v[pre]) S[to] += S[pre], pf[pre] += S[pre], S[pre] = 0, solveC(to); // 注意到第二圈时不要重复计算第一圈的的前缀和,所以直接置零
}
int qpow(int a, int b) { // 快速幂
a %= mod;
if (!b) return 1;
int res = b & 1 ? a : 1;
return res * qpow(a * a % mod, b / 2) % mod;
}
void oper() {
cin >> n >> k;
for (int i = 1; i <= n; i++) {
int a; cin >> a;
v[i].push_back(a), u[a].push_back(i), dp[i][0] = a; // 建图
}
for (int i = 1; i <= n; i++) cin >> A[i];
for (int tt = 1; tt <= 20; tt++) for (int i = 1; i <= n; i++) dp[i][tt] = dp[dp[i][tt - 1]][tt - 1]; // 倍增
for (int i = 1; i <= n; i++) if (!tt[i]) tarjan(i); // 缩点
for (int pre = 1; pre <= n; pre++) for (auto& to : v[pre]) if (id[pre] != id[to]) dout[id[pre]]++; // 计算缩点后出度为0的强连通分量
for (int i = 1; i <= scc_cnt; i++) if (!dout[i]) for (auto& ver : LT[i]) inC[ver] = 1; // 这些强连通分量内的点记为环内点
queue<int> q; for (int i = 1; i <= n; i++) if (inC[i]) q.push(i), distoC[i] = 0; else distoC[i] = 2e18;
while (q.size()) {
int ver = q.front(); q.pop();
for (auto& to : u[ver]) {
if (distoC[to] == 2e18) {
distoC[to] = distoC[ver] + 1;
q.push(to);
}
}
} // 计算每个点到环距离
for (int ver = 1; ver <= n; ver++) {
if (inC[ver]) { // 点在环内
int l = getpos(ver, 1), r = getpos(ver, k % sz[id[ver]] + 1); // l是起始修改点,r是终止修改点
G[l].push_back({ A[ver], r });
(pfC[id[ver]] += k / sz[id[ver]] % mod * A[ver] % mod) %= mod;
}
else if (k >= distoC[ver]) { // 点在环外,可走到环内
int rest = k - distoC[ver] + 1, l = getpos(ver, 1), mid = getpos(ver, distoC[ver]), r = getpos(mid, rest % sz[id[mid]]); // rest表示走到环上后剩余步数
G[mid].push_back({ A[ver], r });
(pfC[id[mid]] += rest / sz[id[mid]] % mod * A[ver] % mod) %= mod;
pf[l] += A[ver], pf[mid] -= A[ver];
}
else { // 点在环外,不可走到环
int l = getpos(ver, 1), r = getpos(ver, k + 1);
pf[l] += A[ver], pf[r] -= A[ver];
}
}
for (int i = 1; i <= n; i++) ste[i] = 0;
for (int i = 1; i <= n; i++) if (!ste[i]) dfs(i); // 树上点树上前缀和计算
for (int i = 1; i <= n; i++) ste[i] = 0;
for (int i = 1; i <= scc_cnt; i++) if (inC[LT[i][0]]) solveC(LT[i][0]); // 环上点环上前缀和计算
for (int i = 1; i <= n; i++) pf[i] %= mod;
for (int i = 1; i <= scc_cnt; i++) for (auto& it : LT[i]) (pf[it] += pfC[i]) %= mod; // 环整体加留到最后计算
int inv = qpow(k % mod, mod - 2);
for (int i = 1; i <= n; i++) cout << pf[i] * inv % mod << " \n"[i == n];
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1; //cin >> t;
while (t--) oper();
return 0;
}