Description
给出一棵 n n 个节点的有根树,根节点为,到达第 i i 个点可以一次往上跳层,跳出树则停止,两种操作,第一种是查询 x x 点出发跳出该棵树需要的步数,第二种是修改
Input
第一行一整数 T T 表示用例组数,每组用例首先输入一整数表示点数,然后输入 n n 个整数,之后输入一整数 m m 表示操作数,最后行每行一个操作
(1≤n,m≤105,1≤ai≤n) ( 1 ≤ n , m ≤ 10 5 , 1 ≤ a i ≤ n )
Output
对于每次 1 1 操作输出查询结果
Sample Input
1
4
1 2 3
1 1 1 1
3
1 4
2 3 2
1 4
Sample Output
4
3
Solution
由于每个点的序必然大于往上跳的点的 dfs d f s 序,以 dfs d f s 序分块,维护三个值 In[u],Out[u],ans[u] I n [ u ] , O u t [ u ] , a n s [ u ] 分别表示 u u 在块内的要跳的下一个点、跳出块后的点、 u u 跳出块需要的步数,在线倍增即可快速得到点的第 y y 层祖先,对于查询操作,只需在块间跳累加对应的值即可,对于修改操作,首先修改 x x 点的三个值,之后对于所处块内的所有点,按 dfs d f s 序从小到大维护这三个值,时间复杂度 O(mn−−√+(m+n)logn) O ( m n + ( m + n ) l o g n )
Code
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
namespace fastIO
{
#define BUF_SIZE 100000
//fread -> read
bool IOerror=0;
inline char nc()
{
static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
if(p1==pend)
{
p1=buf;
pend=buf+fread(buf,1,BUF_SIZE,stdin);
if(pend==p1)
{
IOerror=1;
return -1;
}
}
return *p1++;
}
inline bool blank(char ch)
{
return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';
}
inline void read(int &x)
{
char ch;
while(blank(ch=nc()));
if(IOerror)return;
int sgn=1;
if(ch=='-')sgn=-1;
for(x=ch-'0';(ch=nc())>='0'&&ch<='9';x=x*10+ch-'0');
x=sgn*x;
}
#undef BUF_SIZE
};
using namespace fastIO;
#define maxn 100005
int T,n,q,a[maxn],dep[maxn],p[maxn][18];
int dfn[maxn],index,Id[maxn];
int In[maxn],Out[maxn],ans[maxn];
vector<int>g[maxn];
void dfs(int u)
{
Id[index]=u;
dfn[u]=index++;
for(int i=0;i<g[u].size();i++)
{
dep[g[u][i]]=dep[u]+1;
dfs(g[u][i]);
}
}
int find(int u,int x)
{
if(x>dep[u])return 0;
for(int i=0;i<18;i++)
if((x>>i)&1)u=p[u][i];
return u;
}
int main()
{
read(T);
while(T--)
{
read(n);
memset(p,0,sizeof(p));
for(int i=1;i<=n;i++)g[i].clear();
for(int i=2;i<=n;i++)
{
read(p[i][0]);
g[p[i][0]].push_back(i);
}
for(int i=1;i<=n;i++)read(a[i]);
for(int j=1;j<18;j++)
for(int i=1;i<=n;i++)
p[i][j]=p[p[i][j-1]][j-1];
index=0;
dep[1]=0;
dfs(1);
int m=(int)sqrt(n+0.5);
for(int i=1;i<=n;i++)dfn[i]=dfn[i]/m+1;
for(int i=0;i<n;i++)
{
int u=Id[i],v=find(u,a[u]);
if(dfn[v]!=dfn[u])ans[u]=1,In[u]=0,Out[u]=v;
else ans[u]=ans[v]+1,In[u]=v,Out[u]=Out[v];
}
read(q);
while(q--)
{
int type,u,w;
read(type);
read(u);
if(type==1)
{
int res=0;
while(u)
{
res+=ans[u];
u=Out[u];
}
printf("%d\n",res);
}
else
{
read(w);
a[u]=w;
int v=find(u,a[u]);
if(dfn[u]!=dfn[v])ans[u]=1,In[u]=0,Out[u]=v;
else ans[u]=ans[v]+1,In[u]=v,Out[u]=Out[v];
for(int i=(dfn[u]-1)*m;i<dfn[u]*m;i++)
{
v=Id[i];
if(In[v])ans[v]=ans[In[v]]+1,Out[v]=Out[In[v]];
}
}
}
}
return 0;
}