Question
Solution
考后听别人打得都是什么树剖,线段树,堆。。。
感觉自己打的个链表有点虚啊。。。
我们先弄一个后序遍历,将其中的每一位指向它的下一位,设为
t
o
[
i
]
to[i]
to[i]。
我们设
l
a
s
las
las表示后序遍历中最前的未被标记的点的位置。
操作一:
我们只需跳x次并将每个位置都标记一下即可。并将
l
a
s
las
las更新。
输出跳到最后的位置。
操作二:
我们用倍增跳到它的最远的标记过的祖先。
将这个标记删除,设这个位置为
k
k
k。
如果
k
<
l
a
s
k<las
k<las,就将
t
o
[
k
]
=
l
a
s
to[k]=las
to[k]=las,并将
l
a
s
las
las改成
k
k
k即可。
如果
k
>
l
a
s
k>las
k>las,我们就用另一个变量(设为
o
o
o)跳到一个位置,使得
t
o
[
o
]
>
k
to[o]>k
to[o]>k,
就将
t
o
[
k
]
=
t
o
[
o
]
,
t
o
[
o
]
=
k
to[k]=to[o],to[o]=k
to[k]=to[o],to[o]=k即可。
输出祖先的深度减去输入的x的深度即可。
Code
#include<cstdio>
#include<algorithm>
#define N 100010
using namespace std;
struct node{int u,v;}e[N<<1];
int n,T,e1[N],e2[N],now,dep[N],hav[N],to[N];
int fa[N][17],s=0,dfn[N],fr[N],tot=0,las=1;
inline int read()
{
int x=0; char c=getchar();
while (c<'0' || c>'9') c=getchar();
while (c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x;
}
int cmp(node x,node y) {return x.u==y.u ? x.v<y.v : x.u<y.u;}
void dfs(int x)
{
if (!e2[x]) {dfn[++tot]=x; fr[x]=tot; return;}
for (int p=e1[x],v;p<=e2[x];p++)
{
v=e[p].v;
if (v==fa[x][0]) continue;
dep[v]=dep[x]+1,fa[v][0]=x,dfs(v);
}
dfn[++tot]=x;
fr[x]=tot;
}
int main()
{
n=read(),T=read();to[0]=1;to[n]=n+1;
for (int i=1;i<n;i++)
{
e[(i<<1)-1].u=read(),e[(i<<1)-1].v=read();
e[i<<1].v=e[(i<<1)-1].u,e[i<<1].u=e[(i<<1)-1].v;
to[i]=i+1;
}
sort(e+1,e+n+n-1,cmp);
e1[e[1].u]=1;
for (int i=2;i<=n+n-2;i++)
if (e[i].u!=e[i-1].u)
e2[e[i-1].u]=i-1,e1[e[i].u]=i;
e2[e[n+n-2].u]=n+n-2;
dfs(1);
for (int j=1;j<=16;j++)
for (int i=1;i<=n;i++)
fa[i][j]=fa[fa[i][j-1]][j-1];
for (int i=1,opt,x;i<=T;i++)
{
opt=read(),x=read();
if (opt==1)
{
now=las;hav[now]=1;x--;
while (x--) now=to[now],hav[now]=1;
las=to[now];printf("%d\n",dfn[now]);
}
else
{
s=dep[x];
for (int j=16;j>=0;j--)
if (hav[fr[fa[x][j]]]) x=fa[x][j];
if (fr[x]<las) to[fr[x]]=las,las=fr[x];
else
{
now=las;
while (to[now]<fr[x]) now=to[now];
to[fr[x]]=to[now],to[now]=fr[x];
}
hav[fr[x]]=0;
printf("%d\n",s-dep[x]);
}
}
return 0;
}