codeforces 702E Analysis of Pathes in Functional Graph 倍增
给一个图, 然后给出每条边的权值和一个k值。 让你求出从每个点出发, 走k次能获得的边权的和以及边权的最小值。
用倍增的思想, 求出每个点走一次能到达的点, 权值和以及最小值, 走两次..四次..八次。 这个很容易计算。然后枚举一下所有点就可以了。
#include <iostream> #include <vector> #include <cstdio> #include <cstring> #include <algorithm> #include <complex> #include <cmath> #include <map> #include <set> #include <string> #include <queue> #include <stack> #include <bitset> using namespace std; #define pb(x) push_back(x) #define ll long long #define mk(x, y) make_pair(x, y) #define lson l, m, rt<<1 #define mem(a) memset(a, 0, sizeof(a)) #define rson m+1, r, rt<<1|1 #define mem1(a) memset(a, -1, sizeof(a)) #define mem2(a) memset(a, 0x3f, sizeof(a)) #define rep(i, n, a) for(int i = a; i<n; i++) #define fi first #define se second typedef complex <double> cmx; typedef pair<int, int> pll; const double PI = acos(-1.0); const double eps = 1e-8; const int mod = 1e9+7; const int inf = 1061109567; const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} }; int nxt[100005][35], mn[100005][35]; ll sum[100005][35]; int main() { int n; ll k; cin>>n>>k; for(int i = 0; i < n; i++) { scanf("%d", &nxt[i][0]); } for(int i = 0; i < n; i++) { scanf("%d", &mn[i][0]); sum[i][0] = mn[i][0]; } for(int i = 1; i < 35; i++) { for(int j = 0; j < n; j++) { nxt[j][i] = nxt[nxt[j][i-1]][i-1]; mn[j][i] = min(mn[j][i-1], mn[nxt[j][i-1]][i-1]); sum[j][i] = sum[j][i-1] + sum[nxt[j][i-1]][i-1]; } } for(int j = 0; j < n; j++) { ll ansSum = 0, tmpk = k; int ansMin = inf, pos = j; for(int i = 34; i >= 0; i--) { ll tmp = 1LL<<i; if(tmpk >= tmp) { tmpk -= tmp; ansSum += sum[pos][i]; ansMin = min(ansMin, mn[pos][i]); pos = nxt[pos][i]; } } printf("%I64d %d\n", ansSum, ansMin); } return 0; }