求由該點出發的 k 條邊中的 最小值 和 權值和
直接倍增,模板
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
#define REP(i, a, b) for(register int i = (a), i##_end_ = (b); i <= i##_end_; ++ i)
#define DREP(i, a, b) for(register int i = (a), i##_end_ = (b); i >= i##_end_; -- i)
#define mem(a, b) memset((a), b, sizeof(a))
template<typename T> inline bool chkmin(T &a, const T &b) { return a > b ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }
template <class T>
T read(T sum = 0, T fg = 0)
{
char c = getchar();
while(c < '0' || c > '9') { fg |= c == '-'; c = getchar(); }
while(c >= '0' && c <= '9') { sum = sum * 10 + c - '0'; c = getchar(); }
return fg ? -sum : sum;
}
const int inf = 1e9;
const int Size = 100010;
LL fa[Size][40], sum[Size][40], MIN[Size][40];
int main()
{
#ifndef ONLINE_JUDGE
freopen("graph.in", "r", stdin);
freopen("graph.out", "w", stdout);
#endif
LL n = read<LL>(), k = read<LL>();
REP(i, 1, n) fa[i][0] = read<int>() + 1;
REP(i, 1, n) sum[i][0] = MIN[i][0] = read<LL>();
REP(j, 1, 39) REP(i, 1, n)
{
fa[i][j] = fa[fa[i][j - 1]][j - 1];
sum[i][j] = sum[i][j - 1] + sum[fa[i][j - 1]][j - 1];
MIN[i][j] = min(MIN[i][j - 1], MIN[fa[i][j - 1]][j - 1]);
}
REP(i, 1, n)
{
LL Min = inf;
LL Sum = 0;
int pos = i;
DREP(j, 39, 0)
{
if((k >> j) & 1)
{
Sum += sum[pos][j];
chkmin(Min, MIN[pos][j]);
pos = fa[pos][j];
}
}
printf("%lld %lld\n", Sum, Min);
}
return 0;
}