先离线扫描线,相当于在 \(l\) 这个时刻加入一个点,然后每次令所有点向某个点的方向移动一步,在 \(r\) 时刻查询某个点的位置。
以 \(1\) 为根,对于 \(a_i\) 相当于令 \(1\to a_i\) 这条链上所有点向下移动一步,其他点向上移动一步。
我们需要同时支持这两种操作,但是不能每个点暴力跳,可以考虑树链剖分这两个方面。
容易想到打关于深度的标记。然后我们可以将操作视为:先令 \(1\to a_i\) 所有点向下移动一步,然后给这些点打上深度 \(+1\) 标记,最后给全局所有点打上深度 \(-1\) 标记。
若一个点根据其深度标记走出了所在重链,考虑暴力修改,不难发现一个点至多出现 \(\mathcal O(\log n)\) 次这种情况,快速找到这样的点可以用线段树维护所有重链中距离顶部最近的点的距离。
所有点向下移动同理,当多个点同时到达一个点时,考虑使用并查集将他们合并,这样保证了向下移动的时间正确性。
考虑使用平衡树,可以支持重链某一上半部分的点向下移动,快速判断是否有点重合,时间复杂度 \(\mathcal O(n\log ^ 2n)\)。
点击查看代码
#include <bits/stdc++.h>
namespace Initial {
#define ll int
#define ull unsigned long long
#define fi first
#define se second
#define mkp make_pair
#define pir pair <int, int>
#define pb emplace_back
#define i128 __int128
using namespace std;
const ll maxn = 1e6 + 10, inf = 1e9, mod = 998244353;
ll power(ll a, ll b = mod - 2) {
ll s = 1;
while(b) {
if(b & 1) s = s * a %mod;
a = a * a %mod, b >>= 1;
} return s;
}
template <class T>
const inline ll pls(const T x, const T y) { return x + y >= mod? x + y - mod : x + y; }
template <class T>
const inline void add(T &x, const T y) { x = x + y >= mod? x + y - mod : x + y; }
template <class T>
const inline void chkmax(T &x, const T y) { x = x < y? y : x; }
template <class T>
const inline void chkmin(T &x, const T y) { x = x > y? y : x; }
} using namespace Initial;
namespace Read {
char buf[1 << 22], *p1, *p2;
// #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, (1 << 22) - 10, stdin), p1 == p2)? EOF : *p1++)
template <class T>
const inline void rd(T &x) {
char ch; bool neg = 0;
while(!isdigit(ch = getchar()))
if(ch == '-') neg = 1;
x = ch - '0';
while(isdigit(ch = getchar()))
x = (x << 1) + (x << 3) + ch - '0';
if(neg) x = -x;
}
} using Read::rd;
ll n, n0, m, top[maxn], siz[maxn], son[maxn], dfn[maxn], ti, a[maxn];
ll fa[maxn], tag[maxn], topdep[maxn], tpid[maxn], Tpid, _tp[maxn];
ll qL[maxn], qR[maxn], qS[maxn], ans[maxn], T, pos[maxn], dep[maxn];
vector <ll> to[maxn], vecL[maxn], vecR[maxn], pf[maxn];
void dfs1(ll u) {
siz[u] = 1, dep[u] = dep[fa[u]] + 1;
for(ll v: to[u]) {
dfs1(v), siz[u] += siz[v];
if(siz[v] > siz[son[u]]) son[u] = v;
}
}
void dfs2(ll u, ll tp = 1) {
top[u] = tp, dfn[u] = ++ti, topdep[u] = dep[u] - dep[top[u]];
if(u == tp) tpid[u] = ++Tpid, _tp[Tpid] = u;
else tpid[u] = tpid[tp]; pf[tpid[u]].pb(u);
if(son[u]) dfs2(son[u], tp);
for(ll v: to[u])
if(v ^ son[u]) dfs2(v, v);
}
mt19937 rnd(20090623);
namespace Treap {
struct node { ll lc, rc, w, rnd_val; } b[maxn];
ll tot, d[maxn], tag[maxn], rt[maxn], Fa[maxn];
ll find(ll x) { return d[x] ^ x? d[x] = find(d[x]) : x; }
void addtag(ll p, ll v) { if(p) tag[p] += v, b[p].w += v; }
void pushdown(ll p) {
addtag(b[p].lc, tag[p]);
addtag(b[p].rc, tag[p]);
tag[p] = 0;
}
ll Findnode(ll p, ll w) {
if(!p) return 0;
if(b[p].w == w) return p; pushdown(p);
if(w < b[p].w) return Findnode(b[p].lc, w);
return Findnode(b[p].rc, w);
}
ll Merge(ll p, ll q) {
if(!p || !q) return p | q;
pushdown(p), pushdown(q); Fa[p] = Fa[q] = 0;
if(b[p].rnd_val < b[q].rnd_val)
return Fa[b[p].rc = Merge(b[p].rc, q)] = p;
return Fa[b[q].lc = Merge(p, b[q].lc)] = q;
}
void Split(ll p, ll k, ll &x, ll &y) {
if(!p) return x = y = 0, void();
pushdown(p), Fa[p] = 0;
if(b[p].w <= k)
x = p, Split(b[p].rc, k, b[x].rc, y), Fa[b[x].rc] = x;
else y = p, Split(b[p].lc, k, x, b[y].lc), Fa[b[y].lc] = y;
}
ll Getmin(ll p) {
if(!p) return inf;
if(b[p].lc) return pushdown(p), Getmin(b[p].lc);
return b[p].w;
}
ll ask(ll p) {
ll res = b[p].w;
for(p = Fa[p]; p; p = Fa[p]) res += tag[p];
return res;
}
void Insert(ll &p, ll now) {
ll s1, s2; Split(p, b[now].w, s1, s2);
p = Merge(Merge(s1, now), s2);
}
} using namespace Treap;
struct SGT {
pir mn[maxn << 2];
void build(ll p, ll l, ll r) {
mn[p] = mkp(inf, l);
if(l == r) return; ll mid = l + r >> 1;
build(p << 1, l, mid), build(p << 1|1, mid + 1, r);
}
void modify(ll p, ll l, ll r, ll x, ll v) {
if(l == r) return mn[p].fi = v, void();
ll mid = l + r >> 1;
if(x <= mid) modify(p << 1, l, mid, x, v);
else modify(p << 1|1, mid + 1, r, x, v);
mn[p] = min(mn[p << 1], mn[p << 1|1]);
}
} tr;
void upd(ll k) { tr.modify(1, 1, Tpid, k, Getmin(rt[k])); }
void Mov(ll u) {
ll v = u; u = fa[u];
while(u) {
ll s1, s2; Split(rt[tpid[u]], topdep[u] + T, s1, s2);
ll now; Split(s1, topdep[u] + T - 1, s1, now);
addtag(s1, 1); rt[tpid[u]] = Merge(s1, s2);
if(now) {
b[now].w = topdep[v] + T; pos[now] = tpid[v];
ll c = Findnode(rt[tpid[v]], b[now].w);
if(c) d[now] = c;
else Insert(rt[tpid[v]], now), upd(tpid[v]);
}
upd(tpid[u]), u = fa[v = top[u]];
}
}
void tag_Mov(ll u) {
while(u) {
ll s1, s2; Split(rt[tpid[u]], topdep[u] + T, s1, s2);
ll now; Split(s1, topdep[u] + T - 1, s1, now);
addtag(s1, 1);
if(now) {
++b[now].w;
ll c = Findnode(s2, b[now].w);
if(c) d[now] = c, now = 0;
} rt[tpid[u]] = Merge(Merge(s1, now), s2);
upd(tpid[u]), u = fa[top[u]];
}
}
ll getans(ll x) { return pf[pos[x]][ask(x) - T]; }
signed main() {
// freopen("p.in", "r", stdin);
rd(n), rd(n0), rd(m);
for(ll i = 2; i <= n; i++) rd(fa[i]), to[fa[i]].pb(i);
dfs1(1), dfs2(1);
for(ll i = 1; i <= n0; i++) rd(a[i]);
for(ll i = 1; i <= m; i++) {
rd(qL[i]), rd(qR[i]), rd(qS[i]);
vecL[qL[i]].pb(i), vecR[qR[i]].pb(i);
} tr.build(1, 1, Tpid); tpid[0] = 1;
for(ll i = 1; i <= n0; i++) {
for(ll x: vecL[i]) {
d[x] = x, b[x].w = topdep[qS[x]] + T;
b[x].rnd_val = rnd();
ll k = pos[x] = tpid[qS[x]];
ll y = Findnode(rt[k], b[x].w);
if(y) d[x] = y;
else Insert(rt[k], x), upd(k);
} Mov(a[i]);
tag_Mov(a[i]), T = i;
while(tr.mn[1].fi < T) {
ll id = tr.mn[1].se;
ll now; Split(rt[id], T - 1, now, rt[id]);
ll u = fa[_tp[id]], _id = tpid[u];
b[now].w = topdep[u] + T;
pos[now] = _id;
ll c = Findnode(rt[_id], b[now].w);
if(c) d[now] = c;
else Insert(rt[_id], now), upd(_id);
upd(id);
}
for(ll j: vecR[i]) ans[j] = getans(find(j));
}
for(ll i = 1; i <= m; i++) printf("%d\n", ans[i]);
return 0;
}