CodeForces 702E Analysis of Pathes in Functional Graph

倍增预处理。

先看一下这张图的结构,因为出度都是$1$,所以路径是唯一的,又因为每个点都有出度,所以必然有环,也就是一直可以走下去。

接下来我们需要记录一些值便于询问:

设$t[i][j]$表示从$i$节点出发,走了${2^j}$步之后,到达的节点编号为$t[i][j]$。

设$s[i][j]$表示从$i$节点出发,走了${2^j}$步之后,路径上的权值和为$s[i][j]$。

设$m[i][j]$表示从$i$节点出发,走了${2^j}$步之后,路径上的权值最小值为$m[i][j]$。

像$RMQ$一样,我们可以$dp$预处理出所有的$t[i][j]$,$s[i][j]$,$m[i][j]$。

然后每次询问,只要沿着路从起点找到终点就可以了。单次询问的复杂度为$O(\log n)$,可以理解为$k$的二进制上哪几位是$1$。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
typedef long long LL;
const double pi=acos(-1.0),eps=1e-8;
void File()
{
    freopen("D:\\in.txt","r",stdin);
    freopen("D:\\out.txt","w",stdout);
}
template <class T>
inline void read(T &x)
{
    char c = getchar(); x = 0;while(!isdigit(c)) c = getchar();
    while(isdigit(c)) { x = x * 10 + c - '0'; c = getchar();  }
}

const int maxn=100010;
int n,f[maxn],w[maxn];
LL t[maxn][45],s[maxn][45],m[maxn][45],k;
LL b[maxn];

int main()
{
    b[0]=1; for(int i=1;i<=40;i++) b[i]=2*b[i-1];
    scanf("%d%lld",&n,&k);
    for(int i=0;i<n;i++) scanf("%d",&f[i]);
    for(int i=0;i<n;i++) scanf("%lld",&w[i]);
    for(int i=0;i<n;i++) m[i][0]=s[i][0]=w[i], t[i][0]=f[i];

    for(int i=1;i<=40;i++)
    {
        for(int j=0;j<n;j++)
        {
            m[j][i]=min(m[j][i-1],m[t[j][i-1]][i-1]);
            s[j][i]=s[j][i-1]+s[t[j][i-1]][i-1];
            t[j][i]=t[t[j][i-1]][i-1];
        }
    }

    for(int i=0;i<n;i++)
    {
        LL sum=0,Min=w[i]; int tmp=i;
        for(int j=40;j>=0;j--)
        {
            if(k&((LL)1<<(LL)j))
            {
                int pos=j;
                sum=sum+s[tmp][pos];
                Min=min(Min,m[tmp][pos]);
                tmp=t[tmp][pos];
            }
        }

        printf("%lld %lld\n",sum,Min);
    }
    return  0;
}

 

posted @ 2016-08-24 20:46  Fighting_Heart  阅读(266)  评论(0编辑  收藏  举报