Задача вимагає реалізації запитів для знаходження найменшого спільного предка (НСП) пар вершин. Дерево задане і залишається незмінним протягом усіх запитів. Використаємо алгоритм бінарного підйому.
Реалізація алгоритму
Оголосимо робочі масиви, що використовуються в алгоритмі бінарного підйому.
#define MAX 100010
#define LOGMAX 18
vector<int> g[MAX];
int d[MAX], f[MAX];
int up[MAX][LOGMAX];Функція dfs виконує обхід дерева в глибину починаючи з вершини та будує таблицю предків за допомогою методу бінарного підйому.
void dfs (int v, int p = 0, int len = 0)
{
d[v] = timer++;
up[v][0] = p;
for (int i = 1; i <= l; i++)
up[v][i] = up[up[v][i-1]][i-1];
for (int to : g[v])
if (to != p) dfs (to, v, len + 1);
f[v] = timer++;
}Функція Parent перевіряє, чи є вершина предком вершини .
int Parent(int a, int b)
{
return (d[a] <= d[b]) && (f[a] >= f[b]);
}Функція LCA обчислює найменшого спільного предка вершин та .
int LCA (int a, int b)
{
if (Parent(a, b)) return a;
if (Parent(b, a)) return b;
for (int i = l; i >= 0; i--)
if (!Parent(up[a][i], b)) a = up[a][i];
return up[a][0];
}Основна частина програми. Зчитуємо вхідні дані.
scanf("%d %d",&n,&m);Знаходимо мінімальне значення таке, що 2^l > n.
l = 1;
while ((1 << l) <= n) l++;Зчитуємо дані та будуємо дерево.
for (i = 1; i <= n - 1; i++)
{
scanf("%d",&v);
g[v].push_back(i);
g[i].push_back(v);
}Запускаємо обхід у глибину, під час якого будується структура даних, необхідна для алгоритму бінарного підйому.
timer = 0;
dfs(0);Зчитуємо дані, необхідні для генерації запитів.
scanf("%d %d",&a1,&a2);
scanf("%lld %lld %lld",&x,&y,&z);Генеруємо запити, обробляємо їх послідовно та обчислюємо необхідну суму.
v = sum = 0;
for (i = 0; i < m; i++)
{
v = LCA((a1 + v) % n, a2);
sum += v;
a1 = (x * a1 + y * a2 + z) % n;
a2 = (x * a2 + y * a1 + z) % n;
}Виводимо відповідь.
printf("%lld\n",sum);