【UOJ 668】一个图的问题

【题目描述】:

有一个n个点n条边的有向图(每个点一条出边,可能有自环,节点编号0~N-1),每条边为,意思是i指向f(i)的边权为w(i)的边,现在小A想知道,对于每个点的si和mi。

si:由i出发经过k条边,这k条边的权值和。

mi:由i出发经过k条边,这k条边的权值最小值。

【输入描述】:

第一行两个数n和k

第二行n个数f(i)

第三行n个数w(i)

【输出描述】:

每行两个数si和mi

【样例输入】:

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

【样例输出】:

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

【时间限制、数据范围及描述】:

时间:1s 空间:512M

30%的数据:n,k<=1000。

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

题解:30分的暴力dfs如下(考场没想到是倍增阿巴阿巴阿巴~等我写好倍增就传代码子~

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=100002;
int n,k,ans1,ans2;
int to[N],w[N];
void dfs(int mn,int now,int pace,int sum){
    if(pace==k) { ans1=sum; ans2=mn; return ; }
    dfs(min(w[now],mn),to[now],pace+1,sum+w[now]);
}
int main(){
    freopen("graph.in","r",stdin);
    freopen("graph.out","w",stdout);
    scanf("%d %d",&n,&k);
    for(int i=0;i<n;i++) { scanf("%d",&to[i]); }
    for(int i=0;i<n;i++) { scanf("%d",& w[i]); }
    for(int i=0;i<n;i++) {
        dfs(0x3f3f3f3f,i,0,0);
        printf("%d %d
",ans1,ans2);
    }
    return 0;
}

 倍增就像这样阿巴阿巴~~~

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=1e5+5;
const int M=41;
const int oo=0x3f3f3f3f;
int n;
ll k;
int to[N][M],mn[N][M];
ll sum[N][M];
int main(){
    scanf("%lld %lld",&n,&k);
    for(int i=0;i<n;i++) { scanf("%lld",&to[i][0]); }
    for(int i=0;i<n;i++){
        scanf("%lld",&sum[i][0]);
        mn[i][0]=sum[i][0];
    }
    for(int i=1;i<M;i++){
        for(int j=0;j<n;j++) to[j][i]=to[to[j][i-1]][i-1];
        for(int j=0;j<n;j++){
            sum[j][i]=sum[j][i-1]+sum[to[j][i-1]][i-1];
            mn[j][i]=min(mn[j][i-1],mn[to[j][i-1]][i-1]);
        }
    }
    for(int i=0;i<n;i++){
        ll s=0,kk=k;
        int m=oo,p=i;
        for (int j=M-1;j>=0;j--){
            if (!kk) break;
            if ((1ll<<j)<=kk) {
                kk-=1ll<<j; s+=sum[p][j];
                m=min(m,mn[p][j]); p=to[p][j];
            }
        }
        printf("%lld %d
",s,m);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/wuhu-JJJ/p/13770389.html