题目大意
共
q
q
q 组询问,对于每一组询问有长度为
n
n
n 的序列
p
p
p,
p
i
p_i
pi 表示第
i
i
i 个人的下一位是
p
i
p_i
pi。
求每一个点所在环的长度。
关于解法
本题是一道记忆化搜索题(我不会 Tarjan 缩点),从而减少时间复杂度。题目大意请参考 CF1249B1。
我们发现如果暴力搜索的话对于每一个点我们都会一直搜索直到环,而这个算法会让有许多点重复走过多次,是没有意义的,所以我们想到了记忆化搜索。
暴力搜索时间复杂度是
O
(
∑
n
2
)
O(\sum n^2)
O(∑n2),记忆化搜索的时间复杂度是
O
(
∑
n
)
O(\sum n)
O(∑n)。
代码
#include<bits/stdc++.h>
using namespace std;
int e[200010],q,n,cnt,t,f[200010],ans[200010];//记忆化搜索
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
return x*f;
}
void write(int x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
return;
}
inline int search(int pos,int t,int cnt)
{
f[pos]=1;
if(t==e[pos]) return ans[pos]=cnt+1;
else return ans[pos]=search(e[pos],t,cnt+1);
}
int main()
{
q=read();
while(q--)
{
n=read();
memset(e,0,sizeof(e)),memset(f,0,sizeof(f));
for(int i=1;i<=n;i++) e[i]=read();
for(int i=1;i<=n;i++) if(!f[i]) search(i,i,0);
for(int i=1;i<=n;i++) write(ans[i]),printf(" ");
printf("\n");
}
return 0;
}