倍增

求由該點出發的 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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章