Loading

【题解】P7446 [Ynoi2007] rfplca

双倍经验:CF1491H Yuezheng Ling and Dynamic Tree

好耶,是南北!!!1

思路

小清新分块。

子问题:P3203 [HNOI2010]弹飞绵羊

因为 \(a_i < i\),所以无需考虑父子顺序,祖先结点只有可能在前缀 \([1, i]\) 中。

所以可以类比一下,考虑维护 \(anc_i\) 表示当前树上 \(i\) 一直向上跳可以到达的第一个块外祖先,\(fa_i\) 表示 \(i\) 当前的父结点。

修改的时候:

  1. 修改整块。

    • 至多 \(\sqrt{n}\) 次操作后,该块内的所有 \(a_i\) 都会至少和初始值相差 \(\sqrt{n}\),也就是父结点不在该块内。所以 \(anc_i = a_i\)

    • 反之考虑暴力重构,每次 \(O(\sqrt{n})\),至多 \(O(\sqrt{n})\) 次,共 \(O(\sqrt{n})\) 块,总复杂度是 \(O(n \sqrt{n})\)

  2. 修改散块,暴力重构该块即可。

查询时可以用类似树剖 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;
}
posted @ 2023-01-17 08:22  kymru  阅读(26)  评论(0编辑  收藏  举报