版权声明:欢迎dalao指出错误暴踩本SD,蒟蒻写的博客转载也要吱一声 https://blog.csdn.net/enjoy_pascal/article/details/82952052
description
有一个n个点n条边的有向图,每条边为<i,f(i),w(i)>,意思是i指向f(i)的边权为w(i)的边,现在小A想知道,对于每个点的si和mi。
si:由i出发经过k条边,这k条边的权值和。
mi:由i出发经过k条边,这k条边的权值最小值。
analysis
-
正解倍增
-
每个点出度是 ,就是说点会向指定的方向跳,所以就算不是树也可以倍增
-
可以 时间预处理出第 点跳 步所到的点、边权和与边权最小值,和普通倍增一样
-
然后每个点再走 步,走的过程中统计答案
-
不用判环,因为倍增预处理的信息一直都在一个环里面转
code
#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXN 100005
#define ll long long
#define INF 1000000007
#define fo(i,a,b) for (register ll i=a;i<=b;++i)
#define fd(i,a,b) for (register ll i=a;i>=b;--i)
using namespace std;
ll a[MAXN],b[MAXN];
ll pow[40];
ll n,k;
struct node
{
ll tov,sum,mn;
}f[MAXN][40];
__attribute__((optimize("-O3")))
ll read()
{
ll x=0,f=1;
char ch=getchar();
while (ch<'0' || '9'<ch)
{
if (ch=='-')f=-1;
ch=getchar();
}
while ('0'<=ch && ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
__attribute__((optimize("-O3")))
int main()
{
//freopen("T2.in","r",stdin);
n=read()-1,k=read();
fo(i,0,n)f[i][0].tov=read();
fo(i,0,n)f[i][0].sum=f[i][0].mn=read();
pow[0]=1;
fo(i,1,35)pow[i]=pow[i-1]*2;
fo(j,1,35)
fo(i,0,n)
{
f[i][j].tov=f[f[i][j-1].tov][j-1].tov;
f[i][j].sum=f[i][j-1].sum+f[f[i][j-1].tov][j-1].sum;
f[i][j].mn=min(f[i][j-1].mn,f[f[i][j-1].tov][j-1].mn);
}
fo(i,0,n)
{
ll s=0,m=INF,where=i;
for (register ll j=35,l=k;j>=0 && l;--j)
if (l>=pow[j])
{
l-=pow[j];
m=min(m,f[where][j].mn),
s+=f[where][j].sum;
where=f[where][j].tov;
}
printf("%lld %lld\n",s,m);
}
return 0;
}