版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39972971/article/details/89217141
【题目链接】
【思路要点】
- 将询问 按照 为第一关键字, 为第二关键字排序,那么首先,所有询问只会收到其之前的询问的影响,因此我们可以依次处理它们。
- 其次,可以发现,如此排序后,排在前面的询问将比排在后面的询问先到达任何一个两个询问都会到达的点。
- 考虑记录 表示 将被占用直到 时,对于每个询问,首先找到第一个访问时仍然被占用的节点,获得答案,再更新成功访问的节点的占用时间。
- 注意到访问时间、占用时间均为关于节点深度的一次函数,比较它们的大小可以将节点深度移项,看做一次函数与常数的比较。
- 因此,用树链剖分 + 线段树优化这个过程即可。
- 时间复杂度 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 2e5 + 5; const int cipher = -1e9; typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct SegmentTree { struct Node { int lc, rc; int tag, Max, depth; } a[MAXN * 2]; int root, size, n, depth[MAXN]; void update(int root) { a[root].Max = max(a[a[root].lc].Max, a[a[root].rc].Max); a[root].depth = max(a[a[root].lc].depth, a[a[root].rc].depth); } void build(int &root, int l, int r) { root = ++size; a[root].Max = -2e9; a[root].tag = cipher; if (l == r) { a[root].depth = depth[l]; return; } int mid = (l + r) / 2; build(a[root].lc, l, mid); build(a[root].rc, mid + 1, r); update(root); } void init(int x, int *y) { n = x, size = 0; for (int i = 1; i <= n; i++) depth[i] = 2 * y[i]; build(root, 1, n); } void pushdown(int root) { if (a[root].tag != cipher && a[root].lc) { a[a[root].lc].Max = a[root].tag + a[a[root].lc].depth; a[a[root].lc].tag = a[root].tag; a[a[root].rc].Max = a[root].tag + a[a[root].rc].depth; a[a[root].rc].tag = a[root].tag; a[root].tag = cipher; } } void modify(int root, int l, int r, int ql, int qr, int x) { if (l == ql && r == qr) { a[root].Max = x + a[root].depth; a[root].tag = x; return; } pushdown(root); int mid = (l + r) / 2; if (mid >= ql) modify(a[root].lc, l, mid, ql, min(mid, qr), x); if (mid + 1 <= qr) modify(a[root].rc, mid + 1, r, max(mid + 1, ql), qr, x); update(root); } void modify(int l, int r, int x) { modify(root, 1, n, l, r, x); } int query(int root, int l, int r, int ql, int qr, int x) { pushdown(root); int mid = (l + r) / 2; if (l == ql && r == qr) { if (l == r) { if (a[root].Max > x) return l; else return l - 1; } if (a[a[root].rc].Max > x) return query(a[root].rc, mid + 1, r, mid + 1, r, x); else return query(a[root].lc, l, mid, l, mid, x); } if (mid >= qr) return query(a[root].lc, l, mid, ql, qr, x); if (mid + 1 <= ql) return query(a[root].rc, mid + 1, r, ql, qr, x); int tans = query(a[root].rc, mid + 1, r, mid + 1, qr, x); if (tans == mid) return query(a[root].lc, l, mid, ql, mid, x); else return tans; } int query(int l, int r, int x) { return query(root, 1, n, l, r, x); } } ST; vector <int> a[MAXN], points[MAXN]; int y[MAXN], t[MAXN], p[MAXN], ans[MAXN], val[MAXN]; int n, m, depth[MAXN], size[MAXN], son[MAXN]; int timer, father[MAXN], dfn[MAXN], up[MAXN]; void dfs(int pos, int fa) { depth[pos] = depth[fa] + 1; size[pos] = 1, son[pos] = 0; for (auto x : a[pos]) if (x != fa) { dfs(x, pos); size[pos] += size[x]; if (size[x] > size[son[pos]]) son[pos] = x; } } void efs(int pos, int fa, int from) { up[pos] = from; father[pos] = fa; dfn[pos] = ++timer; points[from].push_back(pos); if (son[pos]) efs(son[pos], pos, from); for (auto x : a[pos]) if (x != son[pos] && x != fa) efs(x, pos, x); } bool cmp(int a, int b) { if (t[a] + depth[y[a]] == t[b] + depth[y[b]]) return y[a] < y[b]; else return t[a] + depth[y[a]] < t[b] + depth[y[b]]; } int main() { read(n), read(m); for (int i = 2; i <= n + 1; i++) { int x; read(x), x++; a[x].push_back(i); } dfs(1, 0); efs(1, 0, 1); for (int i = 1; i <= m; i++) { read(y[i]), y[i]++; read(t[i]), p[i] = i; } sort(p + 1, p + m + 1, cmp); static int tmp[MAXN]; for (int i = 1; i <= n + 1; i++) tmp[dfn[i]] = depth[i]; ST.init(n + 1, tmp); ST.modify(1, 1, 2e9); for (int i = 1; i <= m; i++) { int pos = y[p[i]], x = pos, res = 0; while (true) { int f = up[x]; int tmp = ST.query(dfn[f], dfn[x], depth[pos] + t[p[i]]); if (tmp == dfn[f] - 1) res += dfn[x] - dfn[f] + 1; else { res += dfn[x] - tmp; break; } x = father[f]; } x = pos; ans[p[i]] = t[p[i]] + 2 * res; int tres = res; while (tres) { int f = up[x]; if (tres <= dfn[x] - dfn[f] + 1) { ST.modify(dfn[x] - tres + 1, dfn[x], t[p[i]] + 2 * res - depth[pos]); break; } else { tres -= dfn[x] - dfn[f] + 1; ST.modify(dfn[f], dfn[x], t[p[i]] + 2 * res - depth[pos]); } x = father[f]; } } for (int i = 1; i <= m; i++) printf("%d ", ans[i]); return 0; }