题目描述
给定一棵以11号节点为根,由个节点构成的有根树, 共QQ组询问, 每次询问两点间的。
2≤N≤1000000,1≤Q≤500002≤N≤1000000,1≤Q≤50000,时间限制1000ms1000ms, 空间限制8M8M。
输入输出格式
输入格式
第一行两个个正整数NN,。
第二行一共N−1N−1个数, 表示22号,号,⋯⋯,NN号节点的父节点。保证
以下QQ行, 每行表示一组询问。
解题分析
这道题乍一看:woc不是裸的LCA吗?还出在考试里面…
然后看到了空间限制, 瞬间感觉不妙了起来。
只能开22个的intint数组…倍增、树剖、tarjan显然都是不行的, 存个图就GG了…
那么我们咋搞?
因为每个点直接给的fat[i]fat[i], 所以我们可以不需要DFSDFS就能得到每个点的深度。 然后我们可以退而求其次, 模仿倍增LCALCA,每个点维护向上跳N−−√N个点得到的位置。这样我们就可以O(QN−−√)O(QN)解决问题。
但是这样还有问题: 我们需要开3个数组:fatfat,depdep,toto。这样还是会MLEMLE。 然而我们可以发现, 在父子关系中只需要一个点有depdep信息, 一个点有toto信息, 就可以推导出其他的。 所以我们可以把depdep和toto压在一起, 深度为奇数的时候保存toto信息, 深度为偶数的时候保存depdep信息。
代码如下:
#include <cstdio>
#include <cmath>
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define MX 1000010
#define gc getchar()
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
struct int_3 {unsigned char h, m, l;} d[MX], fat[MX];
IN int get(const int_3 &x) {return (x.h << 14) + (x.m << 7) + x.l;}
IN int_3 to(R int x)
{
int_3 ret;
ret.l = x & 127;
ret.m = (x >> 7) & 127;
ret.h = x >> 14;
return ret;
}
int dot, q, dp = 1024;
IN int F(R int x) {return get(fat[x]);}
IN int D(R int x) {return get(d[x]);}
IN int G(R int x) {return D(x) >= dot ? D(F(x)) + 1 : D(x);}
IN int LCA(R int x, R int y)
{
if(G(x) < G(y)) std::swap(x, y);
int ex = G(x) - G(y);
W (ex > dp) if(D(x) < dot) x = F(x), --ex;
else x = D(x) - dot, ex -= dp;
W (ex--) x = F(x);
W (F(x) != F(y))
{
if(D(x) == D(y)) x = F(x), y = F(y);
else x = D(x) - dot, y = D(y) - dot;
}
if(x ^ y) x = F(x);
return x;
}
int main(void)
{
int a, b, now;
in(dot), in(q); d[0] = to(dot);
for (R int i = 2; i <= dot; ++i)
in(a), fat[i] = to(a), d[i] = to(get(d[a]) + 1);
for (R int i = dot; i; --i)
{
if(get(d[i]) & 1)
{
now = i;
for (R int j = 1; j <= 2; ++j) now = get(fat[now]);
d[i] = to(now + dot);//+dot来区分深度信息和跳父节点的信息。
}
}
for (R int k = 9; k; --k)
for (R int i = dot; i; --i)
{
if(get(d[i]) > dot)
{
now = i;
for (R int j = 1; j <= 2; ++j) now = get(d[now]) - dot;
d[i] = to(now + dot);
}
}
W (q--) in(a), in(b), printf("%d\n", LCA(a, b));
}