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; }