[JZOJ100026]【NOIP2017提高A组模拟7.7】图
十分裸的倍增题...之前没看到节点从0开始标号...傻了。
$nxt[i][k]$表示节点$i$跳$2^j$步到达的节点,$mn[i][j]$表示...之间路长度的最小值,$sum[i][j]$表示...的路径长度和。
水。
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <queue> #include <map> #include <vector> using namespace std; #define reg register #define int long long inline char gc() { static const int BS = 1 << 22; static unsigned char buf[BS], *st, *ed; if (st == ed) ed = buf + fread(st = buf, 1, BS, stdin); return st == ed ? EOF : *st++; } #define gc getchar inline int read() { int res = 0;char ch=gc();bool fu=0; while(!isdigit(ch))fu|=(ch=='-'),ch=gc(); while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=gc(); return fu?-res:res; } int n, k; int nxt[100005][40], mn[100005][40], sum[100005][40]; signed main() { n = read(), k = read(); for (reg int i = 1 ; i <= n ; i ++) nxt[i][0] = read() + 1; for (reg int i = 1 ; i <= n ; i ++) sum[i][0] = mn[i][0] = read(); for (reg int j = 1 ; j <= 35 ; j ++) for (reg int i = 1 ; i <= n ; i ++) nxt[i][j] = nxt[nxt[i][j - 1]][j - 1]; for (reg int j = 1 ; j <= 35 ; j ++) for (reg int i = 1 ; i <= n ; i ++) mn[i][j] = min(mn[i][j - 1], mn[nxt[i][j - 1]][j - 1]); for (reg int j = 1 ; j <= 35 ; j ++) for (reg int i = 1 ; i <= n ; i ++) sum[i][j] = sum[i][j - 1] + sum[nxt[i][j - 1]][j - 1]; for (reg int i = 1 ; i <= n ; i ++) { int ans1 = 0, ans2 = 1ll << 62; int now = i; for (reg int j = 35 ; j >= 0 ; j --) { if (k & (1ll << j)) { ans1 += sum[now][j]; ans2 = min(ans2, mn[now][j]); now = nxt[now][j]; } } printf("%lld %lld\n", ans1, ans2); } return 0; }