Thought interrogation in a differential split into \ (Q (R & lt) -q (L -. 1) \) , offline, sorted by the endpoint.
\ (i, z \) a \ (the LCA \) depth is in fact the root \ (I \) node on the path to the root after adding a whole \ (Z \) the length of the path. A a plus, and a detachable answer a monotonous asked enough.
It seems to be persistent with tree line do online.
#include <cstdio>
#include <algorithm>
const int MAXN = 5e4 + 19, MOD = 201314;
class SegmentTree{
private:
struct Node{
int l, r;
int val, tag;
}tr[MAXN << 2];
void push_up(int node){
tr[node].val = tr[node << 1].val + tr[node << 1 | 1].val;
tr[node].val %= MOD;
}
void push_down(int node){
if(tr[node].tag){
tr[node << 1].val += tr[node].tag * (tr[node << 1].r - tr[node << 1].l + 1);
tr[node << 1].val %= MOD;
tr[node << 1].tag += tr[node].tag;
tr[node << 1].tag %= MOD;
tr[node << 1 | 1].val += tr[node].tag * (tr[node << 1 | 1].r - tr[node << 1 | 1].l + 1);
tr[node << 1 | 1].val %= MOD;
tr[node << 1 | 1].tag += tr[node].tag;
tr[node << 1 | 1].tag %= MOD;
tr[node].tag = 0;
}
}
void build(int node, int l, int r){
tr[node].l = l, tr[node].r = r;
if(l == r)
return;
int mid = (l + r) >> 1;
build(node << 1, l, mid);
build(node << 1 | 1, mid + 1, r);
}
void modify(int node, int l, int r, const int& val){
if(tr[node].l >= l && tr[node].r <= r){
tr[node].val += val * (tr[node].r - tr[node].l + 1) % MOD;
tr[node].val %= MOD;
tr[node].tag += val;
tr[node].tag %= MOD;
return;
}
push_down(node);
int mid = (tr[node].l + tr[node].r) >> 1;
if(l <= mid)
modify(node << 1, l, r, val);
if(r > mid)
modify(node << 1 | 1, l, r, val);
push_up(node);
}
int query(int node, int l, int r){
if(tr[node].l >= l && tr[node].r <= r)
return tr[node].val;
push_down(node);
int mid = (tr[node].l + tr[node].r) >> 1,
res = 0;
if(l <= mid)
res += query(node << 1, l, r);
if(r > mid)
res += query(node << 1 | 1, l, r);
return res;
}
public:
void build(int l, int r){
build(1, l, r);
}
void modify(int l, int r, const int& val){
modify(1, l, r, val);
}
int query(int l, int r){
return query(1, l, r);
}
}myTree;
int ans[MAXN];
struct Query{
int r, z, id, tp, val;
void set(int _r, int _z, int _id, int _tp){
r = _r, z = _z, id = _id, tp = _tp;
}
void enable(void){
ans[id] += tp * val;
}
bool operator<(const Query& b)const{
return r < b.r;
}
}query[MAXN << 1];
int n, q;
struct Edge{
int to, next;
}edge[MAXN << 1];
int cnt, head[MAXN];
inline void add(int from, int to){
edge[++cnt].to = to;
edge[cnt].next = head[from];
head[from] = cnt;
}
int ind;
int fa[MAXN], son[MAXN], dep[MAXN], size[MAXN], top[MAXN], dfn[MAXN];
void dfs1(int node, int f){
fa[node] = f, dep[node] = dep[f] + 1, size[node] = 1;
int __max = 0;
for(int i = head[node]; i; i = edge[i].next)
if(edge[i].to != f){
dfs1(edge[i].to, node);
size[node] += size[edge[i].to];
if(size[edge[i].to] > __max)
__max = size[edge[i].to], son[node] = edge[i].to;
}
}
void dfs2(int node, int f, int t){
dfn[node] = ++ind, top[node] = t;
if(son[node])
dfs2(son[node], node, t);
for(int i = head[node]; i; i = edge[i].next)
if(edge[i].to != f && edge[i].to != son[node])
dfs2(edge[i].to, node, edge[i].to);
}
void modifyPath(int x, int y, const int& val){
while(top[x] != top[y]){
if(dep[top[x]] > dep[top[y]])
myTree.modify(dfn[top[x]], dfn[x], val), x = fa[top[x]];
else
myTree.modify(dfn[top[y]], dfn[y], val), y = fa[top[y]];
}
if(dep[x] < dep[y])
myTree.modify(dfn[x], dfn[y], val);
else
myTree.modify(dfn[y], dfn[x], val);
}
int queryPath(int x, int y){
int res = 0;
while(top[x] != top[y]){
if(dep[top[x]] > dep[top[y]])
res += myTree.query(dfn[top[x]], dfn[x]), x = fa[top[x]];
else
res += myTree.query(dfn[top[y]], dfn[y]), y = fa[top[y]];
res %= MOD;
}
if(dep[x] < dep[y])
res += myTree.query(dfn[x], dfn[y]);
else
res += myTree.query(dfn[y], dfn[x]);
return res % MOD;
}
int main(){
std::scanf("%d%d", &n, &q);
myTree.build(1, n);
for(int u, i = 2; i <= n; ++i){
std::scanf("%d", &u);
add(u + 1, i);
}
dfs1(1, 0);
dfs2(1, 0, 1);
for(int l, r, z, i = 1; i <= q; ++i){
std::scanf("%d%d%d", &l, &r, &z); ++r, ++z;
query[i << 1].set(l, z, i, -1);
query[(i << 1) - 1].set(r, z, i, 1);
}
q <<= 1;
std::sort(query + 1, query + 1 + q);
for(int fst = 0, i = 1; i <= q; ++i){
while(fst < query[i].r)
++fst, modifyPath(1, fst, 1);
query[i].val = queryPath(1, query[i].z);
query[i].enable();
}
q >>= 1;
for(int i = 1; i <= q; ++i)
std::printf("%d\n", (ans[i] % MOD + MOD) % MOD);
return 0;
}