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
", ansSum, ansMin);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/yohaha/p/5731970.html