Description
有一个n个点n条边的有向图,每条边为
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)
Solution
我的做法比较麻烦
我找出了每个环,然后求出每个环的答案,再倍增路线,找到环停止
多出来的几步再通过倍增找出
于是我就打了1400+Byte
之后我发现它的k才10次方,直接倍增模拟不就完了吗??
Code
是我的第一个方法,第二个没打
#include<cstdio>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define N 101000
#define ll long long
using namespace std;
int n,fa[N],bz[N],s[N],bz1[N],f[N][17],e[N];
ll K,w[N],g[N][17],d[N][17],h[N],hd[N],sz[N];
void dg(int x)
{
bz[x]=bz1[x]=1;s[++s[0]]=x;h[x]=0;
if(bz[fa[x]])
{
if(bz1[fa[x]])
{
ll jy=w[x],jy1=w[x],jy2=1;
for(int y=fa[x];y!=x;y=fa[y]) jy+=w[y],jy1=min(jy1,w[y]),jy2++;
for(int y=fa[x];y!=x;y=fa[y]) h[y]=jy,hd[y]=jy1,sz[y]=jy2;
h[x]=jy;hd[x]=jy1;sz[x]=jy2;
}
}
else dg(fa[x]);
s[0]--;bz1[x]=0;
}
int main()
{
scanf("%d%lld",&n,&K);
fo(i,1,n) scanf("%d",&fa[i]),fa[i]++;
fo(i,1,n) scanf("%lld",&w[i]);
fo(i,1,n)
if(!bz[i]) dg(i);
fo(i,1,n) f[i][0]=fa[i],g[i][0]=d[i][0]=w[i];
fo(j,1,16) fo(i,1,n)
{
f[i][j]=f[f[i][j-1]][j-1];
g[i][j]=g[i][j-1]+g[f[i][j-1]][j-1];
d[i][j]=min(d[i][j-1],d[f[i][j-1]][j-1]);
}
e[0]=1;fo(i,1,16) e[i]=e[i-1]*2;
fo(j,1,n)
{
int x=j;ll jy=0,k=K,jy1=2147483647;
fd(i,16,0)
if(h[f[x][i]]==0&&k-e[i]>=0)
{
jy=jy+g[x][i];
jy1=min(jy1,d[x][i]);
x=f[x][i],k-=e[i];
}
if(k>0&&h[x]==0&&h[f[x][0]]!=0) jy=jy+g[x][0],jy1=min(jy1,d[x][0]),x=f[x][0],k--;
if(k>sz[x])
{
ll kk=k/sz[x];
jy=jy+h[x]*kk;jy1=min(jy1,hd[x]);
k=k%sz[x];
}
fd(i,16,0)
if(k-e[i]>=0)
{
jy=jy+g[x][i];
jy1=min(jy1,d[x][i]);
x=f[x][i],k-=e[i];
}
printf("%lld %lld\n",jy,jy1);
}
}