#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
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;
}
const int maxn = 50005, inf = 1000000000, mod = 201314;
int n, m, tot, cnt, place, son[maxn], deep[maxn], head[maxn], fa[maxn], belong[maxn], pl[maxn];
struct edge {
int to, next;
} e[maxn];
struct que {
int z, ans1, ans2;
} q[maxn];
struct data {
int num, p;
bool flag;
} a[maxn << 1];
struct seg {
int l, r, sum, tag;
} tr[maxn << 2];
inline bool operator<(data a, data b) {
return a.p < b.p;
}
inline void insert(int u, int v) {
e[++cnt] = (edge){v, head[u]};
head[u] = cnt;
}
inline void dfs1(int x) {
son[x] = 1;
for (int i = head[x]; i; i = e[i].next) {
if (e[i].to == fa[x])continue;
deep[e[i].to] = deep[x] + 1;
fa[e[i].to] = x;
dfs1(e[i].to);
son[x] += son[e[i].to];
}
}
inline void dfs2(int x, int chain) {
pl[x] = ++place;
belong[x] = chain;
int k = n;
for (int i = head[x]; i; i = e[i].next)
if (e[i].to != fa[x] && son[e[i].to] > son[k])
k = e[i].to;
if (k != n)dfs2(e[k].to, chain);
for (int i = head[x]; i; i = e[i].next)
if (e[i].to != fa[x] && e[i].to != k)
dfs2(e[i].to, e[i].to);
}
inline void pushdown(int k) {
if (tr[k].l == tr[k].r || !tr[k].tag)return;
int tag = tr[k].tag;
tr[k].tag = 0;
tr[k << 1].sum += (tr[k << 1].r - tr[k << 1].l + 1) * tag;
tr[k << 1 | 1].sum += (tr[k << 1 | 1].r - tr[k << 1 | 1].l + 1) * tag;
tr[k << 1].tag += tag;
tr[k << 1 | 1].tag += tag;
}
inline void build(int k, int l, int r) {
tr[k].l = l;
tr[k].r = r;
if (l == r)return;
int mid = (l + r) >> 1;
build(k << 1, l, mid);
build(k << 1 | 1, mid + 1, r);
}
inline void update(int k, int x, int y) {
pushdown(k);
int l = tr[k].l, r = tr[k].r;
if (x == l && y == r) {
tr[k].tag++;
tr[k].sum += r - l + 1;
return;
}
int mid = (l + r) >> 1;
if (y <= mid)update(k << 1, x, y);
else if (x > mid)update(k << 1 | 1, x, y);
else update(k << 1, x, mid), update(k << 1 | 1, mid + 1, y);
tr[k].sum = tr[k << 1].sum + tr[k << 1 | 1].sum;
}
inline void solve_update(int x, int f) {
while (belong[x] != belong[f]) {
update(1, pl[belong[x]], pl[x]);
x = fa[belong[x]];
}
update(1, pl[f], pl[x]);
}
inline int query(int k, int x, int y) {
pushdown(k);
int l = tr[k].l, r = tr[k].r;
if (l == x && r == y)return tr[k].sum;
int mid = (l + r) >> 1;
if (y <= mid)return query(k << 1, x, y);
else if (x > mid)return query(k << 1 | 1, x, y);
else return query(k << 1, x, mid) + query(k << 1 | 1, mid + 1, y);
}
inline int solve_query(int x, int f) {
int res = 0;
while (belong[x] != belong[f]) {
res += query(1, pl[belong[x]], pl[x]);
res %= mod;
x = fa[belong[x]];
}
res += query(1, pl[f], pl[x]);
res %= mod;
return res;
}
int main() {
n = read();
m = read();
for (int i = 1; i < n; i++) {
int x = read();
insert(x, i);
}
for (int i = 1; i <= m; i++) {
int l = read(), r = read();
q[i].z = read();
a[++tot].p = l - 1;
a[tot].num = i;
a[tot].flag = 0;
a[++tot].p = r;
a[tot].num = i;
a[tot].flag = 1;
}
build(1, 1, n);
sort(a + 1, a + tot + 1);
dfs1(0);
dfs2(0, 0);
int now = -1;
for (int i = 1; i <= tot; i++) {
while (now < a[i].p)solve_update(++now, 0);
int t = a[i].num;
if (!a[i].flag)q[t].ans1 = solve_query(q[t].z, 0);
else q[t].ans2 = solve_query(q[t].z, 0);
}
for (int i = 1; i <= m; i++)
printf("%d\n", (q[i].ans2 - q[i].ans1 + mod) % mod);
return 0;
}
3626: [LNOI2014]LCA (树链剖分+离线处理)
最新推荐文章于 2022-03-16 23:20:55 发布