【题解】P7446 [Ynoi2007] rfplca
双倍经验:CF1491H Yuezheng Ling and Dynamic Tree
好耶,是南北!!!1
思路
小清新分块。
因为 \(a_i < i\),所以无需考虑父子顺序,祖先结点只有可能在前缀 \([1, i]\) 中。
所以可以类比一下,考虑维护 \(anc_i\) 表示当前树上 \(i\) 一直向上跳可以到达的第一个块外祖先,\(fa_i\) 表示 \(i\) 当前的父结点。
修改的时候:
-
修改整块。
-
至多 \(\sqrt{n}\) 次操作后,该块内的所有 \(a_i\) 都会至少和初始值相差 \(\sqrt{n}\),也就是父结点不在该块内。所以 \(anc_i = a_i\)
-
反之考虑暴力重构,每次 \(O(\sqrt{n})\),至多 \(O(\sqrt{n})\) 次,共 \(O(\sqrt{n})\) 块,总复杂度是 \(O(n \sqrt{n})\)
-
-
修改散块,暴力重构该块即可。
查询时可以用类似树剖 LCA 的方式交替跳。
时间复杂度 \(O(n \sqrt{n})\),不卡常。
另外绫那个题因为评测机波动,导致最优解被人拿了。
卡了三十多发,结果终究不敌天意,我的阿绫啊……
代码
#include <cstdio>
#include <cmath>
#include <vector>
using namespace std;
#define reg register
const int maxn = 4e5 + 5;
const int blk_sz = 1e3 + 5;
int n, m, sqn, tot;
int st[blk_sz], ed[blk_sz], lazy[blk_sz];
int anc[maxn], fa[maxn], bel[maxn], cnt[maxn];
inline int max(const int &a, const int &b) { return (a > b ? a : b); }
#define check(x) (cnt[x] <= sqn)
#define get_anc(x) (check(bel[x]) ? anc[x] : max(fa[x] - lazy[bel[x]], 1))
#define get_fa(x) (check(bel[x]) ? fa[x] : max(fa[x] - lazy[bel[x]], 1))
inline void upd_anc(reg const int& x) { if (check(bel[x])) anc[x] = bel[x] != bel[fa[x]] ? fa[x] : anc[fa[x]]; }
inline void upd_blk2(reg const int& l, reg const int& r, reg const int& x)
{
int er = ed[bel[r]];
for (reg int i(l); i <= r; ++i) fa[i] = max(fa[i] - x, 1);
for (reg int i(l); i <= er; ++i) upd_anc(i);
}
inline void upd_blk1(reg const int& bl, reg const int& x)
{
if (!check(bl)) { lazy[bl] = min(lazy[bl] + x, n); return; }
cnt[bl]++;
for (reg int i(st[bl]); i <= ed[bl]; ++i) fa[i] = max(fa[i] - x, 1), upd_anc(i);
}
inline void modify(reg const int& l, reg const int& r, reg const int& x)
{
if(bel[l] == bel[r]) return upd_blk2(l, r, x);
upd_blk2(l, ed[bel[l]], x); modify(st[bel[r]], r, x);
for (int i(bel[l] + 1); i <= bel[r] - 1; ++i) upd_blk1(i, x);
}
inline int query(int u, int v)
{
while (u != v)
{
reg int au = get_anc(u), av = get_anc(v);
if (bel[au] != bel[av]) bel[au] < bel[av] ? v = av : u = au;
else if (au != av) au > av ? u = au : v = av;
else u > v ? u = get_fa(u) : v = get_fa(v);
}
return u;
}
int main()
{
scanf("%d%d", &n, &m);
fa[1] = anc[1] = 1;
sqn = sqrt(n), tot = (n - 1) / sqn + 1;
for (reg int i(1); i <= tot; ++i)
{
st[i] = (i - 1) * sqn + 1;
ed[i] = i == tot ? n : i * sqn;
for (int j(st[i]); j <= ed[i]; j++) bel[j] = i;
}
for (reg int i(2); i <= n; ++i) scanf("%d", &fa[i]), upd_anc(i);
int op, l, r, x, last_ans = 0;
while (m--)
{
scanf("%d%d%d", &op, &l, &r);
l ^= last_ans, r ^= last_ans;
if (op == 1) scanf("%d", &x), modify(l, r, x ^ last_ans);
else printf("%d\n", last_ans = query(l, r));
}
return 0;
}