[USACO24FEB] Infinite Adventure P
C1942huangjiaxu · · 题解
很深刻的题。
图上行走问题自然想到倍增,先简单尝试一下。
记
但发现走
所以如果遇到了点
我们称
记
但是我们预处理时同样要这样走,所以总时间复杂度为
发现实际上我们记录这个
因为只有走到了,
再来考虑询问,我们先用
这样,我们以
参考代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf=2e18;
const int N=1e5+5;
int n,q,t[N],mx;
int *c[N],*f[61][N];
ll *g[61][N];
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;++i){
scanf("%d",&t[i]);
c[i]=new int[t[i]];
mx=max(mx,t[i]);
for(int j=0;j<=60;++j)f[j][i]=new int[t[i]],g[j][i]=new ll[t[i]];
}
for(int i=1;i<=n;++i)
for(int j=0;j<t[i];++j)scanf("%d",&c[i][j]);
for(int j=1;j<=mx;j<<=1){
for(int i=1;i<=n;++i)if(t[i]==j)for(int k=0;k<j;++k){
int x=c[i][k];ll dt=1;
while(t[x]<j&&dt<inf){
int y=f[60][x][k+dt&t[x]-1];
dt+=g[60][x][k+dt&t[x]-1];
x=y;
}
f[0][i][k]=x,g[0][i][k]=min(inf,dt);
}
for(int l=1;l<=60;++l)for(int i=1;i<=n;++i)if(t[i]==j)for(int k=0;k<j;++k){
int x=f[l-1][i][k];ll dt=g[l-1][i][k];
if(t[x]!=j){
f[l][i][k]=x;
g[l][i][k]=dt;
continue;
}
f[l][i][k]=f[l-1][x][k+dt&j-1];
g[l][i][k]=min(inf,g[l-1][x][k+dt&j-1]+dt);
}
}
while(q--){
int x;ll T,dt,w;
scanf("%d%lld%lld",&x,&T,&dt);
while(dt){
for(int j=60;~j&&dt;--j)if((w=g[j][x][T&t[x]-1])<=dt){
dt-=w;
int ls=t[x];
x=f[j][x][T&t[x]-1];
T+=w;
if(t[x]!=ls)j=61;
}
if(dt){
x=c[x][T&t[x]-1];
++T,--dt;
}
}
printf("%d\n",x);
}
return 0;
}