[JZOJ100026]【NOIP2017提高A组模拟7.7】图

Description

有一个n个点n条边的有向图,每条边为<i,f(i),w(i)>,意思是i指向f(i)的边权为w(i)的边,现在小A想知道,对于每个点的si和mi。
si:由i出发经过k条边,这k条边的权值和。
mi:由i出发经过k条边,这k条边的权值最小值。
 

Input

第一行两个数n和k
第二行n个数f(i)
第三行n个数w(i)

Output

每行两个数si和mi

Sample Input

7 3
1 2 3 4 3 2 6
6 3 1 4 2 2 3

Sample Output

10 1
8 1
7 1
10 2
8 2
7 1
9 3

Data Constraint

30%的数据:n,k<=1000。
100%的数据:N<=10^5,k<=10^10,0<=f(i)<n,w(i)<=10^8。

Hint


十分裸的倍增题...之前没看到节点从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;
}

猜你喜欢

转载自www.cnblogs.com/BriMon/p/9748999.html