P10659 BZOJ3159 决战 题解
\(\text{P10659 BZOJ3159 决战 题解}\)
显然除了反转这个唐氏操作都是很好维护的。反转问题通常的解决方法是 FHQ-Treap 或 LCT。对于本题,LCT 并不需要特殊限制,因此介绍一下 LCT 做法。
simple 的想法是用 LCT 维护时遇到反转操作就下放一次 tag 标记,但由于这样做事实上改变了原树的形态,因而并不可行。然而我们只有通过下放 tag 标记这个操作才能在复杂度正确的前提下正确地维护信息。于是我们不妨建一棵辅助树来维护 LCT 上每棵 Splay 中节点所对应的实际权值。这里建出的辅助树可以理解为一些个 Splay 树的集合,维护每个 LCT 上的 Splay 中的权值信息。不难发现辅助树上的每棵 Splay 要和原树上的形态相同,因此我们可以对原 LCT 上的每个节点维护一个到对应辅助树上任意一点的指针 \(pos\),在维护所有操作时和 LCT 上的 Splay 同步变化。较难维护的是 access 操作,我们需要找到节点权值树上对应的节点,重新连断边来处理。具体见代码。
#include <bits/stdc++.h>
#define N 50005
#define int long long
using namespace std;
int n, m, r;
struct LCT {
struct Node {
int son[2], fa, tg;
int siz, vl, pos, fg;
int dg, sm, mx, mn;
} e[N];
#define lc(i) e[i].son[0]
#define rc(i) e[i].son[1]
#define fa(i) e[i].fa
#define tg(i) e[i].tg
#define siz(i) e[i].siz
#define vl(i) e[i].vl
#define pos(i) e[i].pos
#define fg(i) e[i].fg
#define dg(i) e[i].dg
#define sm(i) e[i].sm
#define mx(i) e[i].mx
#define mn(i) e[i].mn
int isrt(int p) {
return lc(fa(p)) != p && rc(fa(p)) != p;
}
int get(int p) {
return rc(fa(p)) == p;
}
void tag_down(int p) {
swap(lc(p), rc(p));
tg(p) ^= 1;
}
void fag_down(int p, int x) {
fg(p) = pos(p) = x;
}
void dag_down(int p, int x) {
if (!p) return;
sm(p) += siz(p) * x;
vl(p) += x;
mn(p) += x;
mx(p) += x;
dg(p) += x;
}
void push_down(int p) {
if (tg(p)) tag_down(lc(p)), tag_down(rc(p));
if (fg(p)) fag_down(lc(p), fg(p)), fag_down(rc(p), fg(p));
if (dg(p)) dag_down(lc(p), dg(p)), dag_down(rc(p), dg(p));
tg(p) = fg(p) = dg(p) = 0;
}
void update(int p) {
if (!isrt(p)) update(fa(p));
push_down(p);
}
void push_up(int p) {
siz(p) = siz(lc(p)) + siz(rc(p)) + 1;
sm(p) = sm(lc(p)) + sm(rc(p)) + vl(p);
mn(p) = min({mn(lc(p)), mn(rc(p)), vl(p)});
mx(p) = max({mx(lc(p)), mx(rc(p)), vl(p)});
}
void rotate(int p) {
int y = fa(p), z = fa(y), c = get(p);
if (!isrt(y)) e[z].son[get(y)] = p;
fa(e[p].son[c ^ 1]) = y;
e[y].son[c] = e[p].son[c ^ 1];
e[p].son[c ^ 1] = y;
fa(y) = p;
fa(p) = z;
push_up(y);
push_up(p);
}
void splay(int p) {
update(p);
int f = fa(p);
while (!isrt(p)) {
if (!isrt(f)) rotate(get(f) == get(p) ? f : p);
rotate(p);
f = fa(p);
}
}
int kth(int p, int k) {
push_down(p);
if (siz(lc(p)) + 1 == k) return p;
if (siz(lc(p)) >= k) return kth(lc(p), k);
return kth(rc(p), k - siz(lc(p)) - 1);
}
} A, B;
void access(int p) {
int xa = 0, xb = 0;
while (p) {
A.splay(p);
int pos = A.pos(p);
B.splay(pos);
pos = B.kth(pos, A.siz(A.lc(p)) + 1);
B.splay(pos);
A.fag_down(p, pos);
A.fag_down(A.rc(p), B.rc(pos));
A.rc(p) = xa;
B.fa(B.rc(pos)) = 0;
B.rc(pos) = xb;
B.fa(xb) = pos;
xa = p, xb = pos;
A.push_up(p);
B.push_up(pos);
p = A.fa(p);
}
}
void mkrt(int p) {
access(p);
A.splay(p);
B.splay(A.pos(p));
A.tag_down(p);
B.tag_down(A.pos(p));
}
void split(int x, int y) {
mkrt(x);
access(y);
A.splay(y);
B.splay(A.pos(y));
}
void link(int x, int y) {
mkrt(x);
A.fa(x) = y;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m >> r;
B.mn(0) = INT_MAX;
for (int i = 1; i <= n; i++) {
A.siz(i) = B.siz(i) = 1;
A.pos(i) = i;
A.mn(i) = B.mn(i) = INT_MAX;
}
for (int i = 1; i < n; i++) {
int x, y;
cin >> x >> y;
link(x, y);
}
while (m--) {
string s;
int x, y;
cin >> s >> x >> y;
split(x, y);
if (s == "Increase") {
int w;
cin >> w;
B.dag_down(A.pos(y), w);
}
else if (s == "Sum") cout << B.sm(A.pos(y)) << '\n';
else if (s == "Major") cout << B.mx(A.pos(y)) << '\n';
else if (s == "Minor") cout << B.mn(A.pos(y)) << '\n';
else B.tag_down(A.pos(y));
}
return 0;
}

浙公网安备 33010602011771号