- 二维
int f[maxn][maxn][10][10];
inline int highbit(int x) { return 31 - __builtin_clz(x); }
inline int calc(int x, int y, int xx, int yy, int p, int q) {
return max(
max(f[x][y][p][q], f[xx - (1 << p) + 1][yy - (1 << q) + 1][p][q]),
max(f[xx - (1 << p) + 1][y][p][q], f[x][yy - (1 << q) + 1][p][q])
);
}
void init() {
FOR (x, 0, highbit(n) + 1)
FOR (y, 0, highbit(m) + 1)
FOR (i, 0, n - (1 << x) + 1)
FOR (j, 0, m - (1 << y) + 1) {
if (!x && !y) { f[i][j][x][y] = a[i][j]; continue; }
f[i][j][x][y] = calc(
i, j,
i + (1 << x) - 1, j + (1 << y) - 1,
max(x - 1, 0), max(y - 1, 0)
);
}
}
inline int get_max(int x, int y, int xx, int yy) {
return calc(x, y, xx, yy, highbit(xx - x + 1), highbit(yy - y + 1));
}
- 一维
struct RMQ {
int f[22][M];
inline int highbit(int x) { return 31 - __builtin_clz(x); }
void init(int* v, int n) {
FOR (i, 0, n) f[0][i] = v[i];
FOR (x, 1, highbit(n) + 1)
FOR (i, 0, n - (1 << x) + 1)
f[x][i] = min(f[x - 1][i], f[x - 1][i + (1 << (x - 1))]);
}
int get_min(int l, int r) {
assert(l <= r);
int t = highbit(r - l + 1);
return min(f[t][l], f[t][r - (1 << t) + 1]);
}
} rmq;
- 普适
namespace sg {
struct Q {
LL setv;
explicit Q(LL setv = -1): setv(setv) {}
void operator += (const Q& q) { if (q.setv != -1) setv = q.setv; }
};
struct P {
LL min;
explicit P(LL min = INF): min(min) {}
void up(Q& q) { if (q.setv != -1) min = q.setv; }
};
template<typename T>
P operator & (T&& a, T&& b) {
return P(min(a.min, b.min));
}
P p[maxn << 2];
Q q[maxn << 2];
#define lson o * 2, l, (l + r) / 2
#define rson o * 2 + 1, (l + r) / 2 + 1, r
void up(int o, int l, int r) {
if (l == r) p[o] = P();
else p[o] = p[o * 2] & p[o * 2 + 1];
p[o].up(q[o]);
}
void down(int o, int l, int r) {
q[o * 2] += q[o]; q[o * 2 + 1] += q[o];
q[o] = Q();
up(lson); up(rson);
}
template<typename T>
void build(T&& f, int o = 1, int l = 1, int r = n) {
if (l == r) q[o] = f(l);
else { build(f, lson); build(f, rson); q[o] = Q(); }
up(o, l, r);
}
P query(int ql, int qr, int o = 1, int l = 1, int r = n) {
if (ql > r || l > qr) return P();
if (ql <= l && r <= qr) return p[o];
down(o, l, r);
return query(ql, qr, lson) & query(ql, qr, rson);
}
void update(int ql, int qr, const Q& v, int o = 1, int l = 1, int r = n) {
if (ql > r || l > qr) return;
if (ql <= l && r <= qr) q[o] += v;
else {
down(o, l, r);
update(ql, qr, v, lson); update(ql, qr, v, rson);
}
up(o, l, r);
}
}
- SET + ADD
struct IntervalTree {
#define ls o * 2, l, m
#define rs o * 2 + 1, m + 1, r
static const LL M = maxn * 4, RS = 1E18 - 1;
LL addv[M], setv[M], minv[M], maxv[M], sumv[M];
void init() {
memset(addv, 0, sizeof addv);
fill(setv, setv + M, RS);
memset(minv, 0, sizeof minv);
memset(maxv, 0, sizeof maxv);
memset(sumv, 0, sizeof sumv);
}
void maintain(LL o, LL l, LL r) {
if (l < r) {
LL lc = o * 2, rc = o * 2 + 1;
sumv[o] = sumv[lc] + sumv[rc];
minv[o] = min(minv[lc], minv[rc]);
maxv[o] = max(maxv[lc], maxv[rc]);
} else sumv[o] = minv[o] = maxv[o] = 0;
if (setv[o] != RS) { minv[o] = maxv[o] = setv[o]; sumv[o] = setv[o] * (r - l + 1); }
if (addv[o]) { minv[o] += addv[o]; maxv[o] += addv[o]; sumv[o] += addv[o] * (r - l + 1); }
}
void build(LL o, LL l, LL r) {
if (l == r) addv[o] = a[l];
else {
LL m = (l + r) / 2;
build(ls); build(rs);
}
maintain(o, l, r);
}
void pushdown(LL o) {
LL lc = o * 2, rc = o * 2 + 1;
if (setv[o] != RS) {
setv[lc] = setv[rc] = setv[o];
addv[lc] = addv[rc] = 0;
setv[o] = RS;
}
if (addv[o]) {
addv[lc] += addv[o]; addv[rc] += addv[o];
addv[o] = 0;
}
}
void update(LL p, LL q, LL o, LL l, LL r, LL v, LL op) {
if (p <= r && l <= q)
if (p <= l && r <= q) {
if (op == 2) { setv[o] = v; addv[o] = 0; }
else addv[o] += v;
} else {
pushdown(o);
LL m = (l + r) / 2;
update(p, q, ls, v, op); update(p, q, rs, v, op);
}
maintain(o, l, r);
}
void query(LL p, LL q, LL o, LL l, LL r, LL add, LL& ssum, LL& smin, LL& smax) {
if (p > r || l > q) return;
if (setv[o] != RS) {
LL v = setv[o] + add + addv[o];
ssum += v * (min(r, q) - max(l, p) + 1);
smin = min(smin, v);
smax = max(smax, v);
} else if (p <= l && r <= q) {
ssum += sumv[o] + add * (r - l + 1);
smin = min(smin, minv[o] + add);
smax = max(smax, maxv[o] + add);
} else {
LL m = (l + r) / 2;
query(p, q, ls, add + addv[o], ssum, smin, smax);
query(p, q, rs, add + addv[o], ssum, smin, smax);
}
}
} IT;
- 区间取 min,区间求和。
namespace R {
#define lson o * 2, l, (l + r) / 2
#define rson o * 2 + 1, (l + r) / 2 + 1, r
int m1[N], m2[N], cm1[N];
LL sum[N];
void up(int o) {
int lc = o * 2, rc = lc + 1;
m1[o] = max(m1[lc], m1[rc]);
sum[o] = sum[lc] + sum[rc];
if (m1[lc] == m1[rc]) {
cm1[o] = cm1[lc] + cm1[rc];
m2[o] = max(m2[lc], m2[rc]);
} else {
cm1[o] = m1[lc] > m1[rc] ? cm1[lc] : cm1[rc];
m2[o] = max(min(m1[lc], m1[rc]), max(m2[lc], m2[rc]));
}
}
void mod(int o, int x) {
if (x >= m1[o]) return;
assert(x > m2[o]);
sum[o] -= 1LL * (m1[o] - x) * cm1[o];
m1[o] = x;
}
void down(int o) {
int lc = o * 2, rc = lc + 1;
mod(lc, m1[o]); mod(rc, m1[o]);
}
void build(int o, int l, int r) {
if (l == r) { int t; read(t); sum[o] = m1[o] = t; m2[o] = -INF; cm1[o] = 1; }
else { build(lson); build(rson); up(o); }
}
void update(int ql, int qr, int x, int o, int l, int r) {
if (r < ql || qr < l || m1[o] <= x) return;
if (ql <= l && r <= qr && m2[o] < x) { mod(o, x); return; }
down(o);
update(ql, qr, x, lson); update(ql, qr, x, rson);
up(o);
}
int qmax(int ql, int qr, int o, int l, int r) {
if (r < ql || qr < l) return -INF;
if (ql <= l && r <= qr) return m1[o];
down(o);
return max(qmax(ql, qr, lson), qmax(ql, qr, rson));
}
LL qsum(int ql, int qr, int o, int l, int r) {
if (r < ql || qr < l) return 0;
if (ql <= l && r <= qr) return sum[o];
down(o);
return qsum(ql, qr, lson) + qsum(ql, qr, rson);
}
}
- ADD
namespace tree {
#define mid ((l + r) >> 1)
#define lson ql, qr, l, mid
#define rson ql, qr, mid + 1, r
struct P {
LL add, sum;
int ls, rs;
} tr[maxn * 45 * 2];
int sz = 1;
int N(LL add, int l, int r, int ls, int rs) {
tr[sz] = {add, tr[ls].sum + tr[rs].sum + add * (len[r] - len[l - 1]), ls, rs};
return sz++;
}
int update(int o, int ql, int qr, int l, int r, LL add) {
if (ql > r || l > qr) return o;
const P& t = tr[o];
if (ql <= l && r <= qr) return N(add + t.add, l, r, t.ls, t.rs);
return N(t.add, l, r, update(t.ls, lson, add), update(t.rs, rson, add));
}
LL query(int o, int ql, int qr, int l, int r, LL add = 0) {
if (ql > r || l > qr) return 0;
const P& t = tr[o];
if (ql <= l && r <= qr) return add * (len[r] - len[l - 1]) + t.sum;
return query(t.ls, lson, add + t.add) + query(t.rs, rson, add + t.add);
}
}
最优化问题一定要用全局变量大力剪枝,而且左右儿子先递归潜力大的
- 维护信息
- 带重构(适合在线)
- 插入时左右儿子要标记为
null
。
namespace kd {
const int K = 2, inf = 1E9, M = N;
const double lim = 0.7;
struct P {
int d[K], l[K], r[K], sz, val;
LL sum;
P *ls, *rs;
P* up() {
sz = ls->sz + rs->sz + 1;
sum = ls->sum + rs->sum + val;
FOR (i, 0, K) {
l[i] = min(d[i], min(ls->l[i], rs->l[i]));
r[i] = max(d[i], max(ls->r[i], rs->r[i]));
}
return this;
}
} pool[M], *null = new P, *pit = pool;
static P *tmp[M], **pt;
void init() {
null->ls = null->rs = null;
FOR (i, 0, K) null->l[i] = inf, null->r[i] = -inf;
null->sum = null->val = 0;
null->sz = 0;
}
P* build(P** l, P** r, int d = 0) { // [l, r)
if (d == K) d = 0;
if (l >= r) return null;
P** m = l + (r - l) / 2; assert(l <= m && m < r);
nth_element(l, m, r, [&](const P* a, const P* b){
return a->d[d] < b->d[d];
});
P* o = *m;
o->ls = build(l, m, d + 1); o->rs = build(m + 1, r, d + 1);
return o->up();
}
P* Build() {
pt = tmp; FOR (it, pool, pit) *pt++ = it;
return build(tmp, pt);
}
inline bool inside(int p[], int q[], int l[], int r[]) {
FOR (i, 0, K) if (r[i] < q[i] || p[i] < l[i]) return false;
return true;
}
LL query(P* o, int l[], int r[]) {
if (o == null) return 0;
FOR (i, 0, K) if (o->r[i] < l[i] || r[i] < o->l[i]) return 0;
if (inside(o->l, o->r, l, r)) return o->sum;
return query(o->ls, l, r) + query(o->rs, l, r) +
(inside(o->d, o->d, l, r) ? o->val : 0);
}
void dfs(P* o) {
if (o == null) return;
*pt++ = o; dfs(o->ls); dfs(o->rs);
}
P* ins(P* o, P* x, int d = 0) {
if (d == K) d = 0;
if (o == null) return x->up();
P*& oo = x->d[d] <= o->d[d] ? o->ls : o->rs;
if (oo->sz > o->sz * lim) {
pt = tmp; dfs(o); *pt++ = x;
return build(tmp, pt, d);
}
oo = ins(oo, x, d + 1);
return o->up();
}
}
- 维护信息
- 带修改(适合离线)
namespace kd {
const int K = 3, inf = 1E9, M = N << 3;
extern struct P* null;
struct P {
int d[K], l[K], r[K], val;
int Max;
P *ls, *rs, *fa;
P* up() {
Max = max(val, max(ls->Max, rs->Max));
FOR (i, 0, K) {
l[i] = min(d[i], min(ls->l[i], rs->l[i]));
r[i] = max(d[i], max(ls->r[i], rs->r[i]));
}
return ls->fa = rs->fa = this;
}
} pool[M], *null = new P, *pit = pool;
void upd(P* o, int val) {
o->val = val;
for (; o != null; o = o->fa)
o->Max = max(o->Max, val);
}
static P *tmp[M], **pt;
void init() {
null->ls = null->rs = null;
FOR (i, 0, K) null->l[i] = inf, null->r[i] = -inf;
null->Max = null->val = 0;
}
P* build(P** l, P** r, int d = 0) { // [l, r)
if (d == K) d = 0;
if (l >= r) return null;
P** m = l + (r - l) / 2; assert(l <= m && m < r);
nth_element(l, m, r, [&](const P* a, const P* b){
return a->d[d] < b->d[d];
});
P* o = *m;
o->ls = build(l, m, d + 1); o->rs = build(m + 1, r, d + 1);
return o->up();
}
P* Build() {
pt = tmp; FOR (it, pool, pit) *pt++ = it;
P* ret = build(tmp, pt); ret->fa = null;
return ret;
}
inline bool inside(int p[], int q[], int l[], int r[]) {
FOR (i, 0, K) if (r[i] < q[i] || p[i] < l[i]) return false;
return true;
}
int query(P* o, int l[], int r[]) {
if (o == null) return 0;
FOR (i, 0, K) if (o->r[i] < l[i] || r[i] < o->l[i]) return 0;
if (inside(o->l, o->r, l, r)) return o->Max;
int ret = 0;
if (o->val > ret && inside(o->d, o->d, l, r)) ret = max(ret, o->val);
if (o->ls->Max > ret) ret = max(ret, query(o->ls, l, r));
if (o->rs->Max > ret) ret = max(ret, query(o->rs, l, r));
return ret;
}
}
- 最近点对
- 要用全局变量大力剪枝
namespace kd {
const int K = 3;
const int M = N;
const int inf = 1E9 + 100;
struct P {
int d[K];
int l[K], r[K];
P *ls, *rs;
P* up() {
FOR (i, 0, K) {
l[i] = min(d[i], min(ls->l[i], rs->l[i]));
r[i] = max(d[i], max(ls->r[i], rs->r[i]));
}
return this;
}
} pool[M], *null = new P, *pit = pool;
static P *tmp[M], **pt;
void init() {
null->ls = null->rs = null;
FOR (i, 0, K) null->l[i] = inf, null->r[i] = -inf;
}
P* build(P** l, P** r, int d = 0) { // [l, r)
if (d == K) d = 0;
if (l >= r) return null;
P** m = l + (r - l) / 2;
nth_element(l, m, r, [&](const P* a, const P* b){
return a->d[d] < b->d[d];
});
P* o = *m;
o->ls = build(l, m, d + 1); o->rs = build(m + 1, r, d + 1);
return o->up();
}
LL eval(P* o, int d[]) {
// ...
}
LL dist(int d1[], int d2[]) {
// ...
}
LL S;
LL query(P* o, int d[]) {
if (o == null) return 0;
S = max(S, dist(o->d, d));
LL mdl = eval(o->ls, d), mdr = eval(o->rs, d);
if (mdl < mdr) {
if (S > mdl) S = max(S, query(o->ls, d));
if (S > mdr) S = max(S, query(o->rs, d));
} else {
if (S > mdr) S = max(S, query(o->rs, d));
if (S > mdl) S = max(S, query(o->ls, d));
}
return S;
}
P* Build() {
pt = tmp; FOR (it, pool, pit) *pt++ = it;
return build(tmp, pt);
}
}
- 注意:0 是无效下标
namespace bit {
LL c[M];
inline int lowbit(int x) { return x & -x; }
void add(int x, LL v) {
for (int i = x; i < M; i += lowbit(i))
c[i] += v;
}
LL sum(int x) {
LL ret = 0;
for (int i = x; i > 0; i -= lowbit(i))
ret += c[i];
return ret;
}
int kth(LL k) {
int p = 0;
for (int lim = 1 << 20; lim; lim /= 2)
if (p + lim < M && c[p + lim] < k) {
p += lim;
k -= c[p];
}
return p + 1;
}
LL sum(int l, int r) { return sum(r) - sum(l - 1); }
void add(int l, int r, LL v) { add(l, v); add(r + 1, -v); }
}
- 区间修改 & 区间查询(单点修改,查询前缀和的前缀和)
namespace bit {
int c[maxn], cc[maxn];
inline int lowbit(int x) { return x & -x; }
void add(int x, int v) {
for (int i = x; i <= n; i += lowbit(i)) {
c[i] += v; cc[i] += x * v;
}
}
void add(int l, int r, int v) { add(l, v); add(r + 1, -v); }
int sum(int x) {
int ret = 0;
for (int i = x; i > 0; i -= lowbit(i))
ret += (x + 1) * c[i] - cc[i];
return ret;
}
int sum(int l, int r) { return sum(r) - sum(l - 1); }
}
- 单点修改,查询前缀和的前缀和的前缀和(有用才怪)
namespace bit {
LL c[N], cc[N], ccc[N];
inline LL lowbit(LL x) { return x & -x; }
void add(LL x, LL v) {
for (LL i = x; i < N; i += lowbit(i)) {
c[i] = (c[i] + v) % MOD;
cc[i] = (cc[i] + x * v) % MOD;
ccc[i] = (ccc[i] + x * x % MOD * v) % MOD;
}
}
void add(LL l, LL r, LL v) { add(l, v); add(r + 1, -v); }
LL sum(LL x) {
static LL INV2 = (MOD + 1) / 2;
LL ret = 0;
for (LL i = x; i > 0; i -= lowbit(i))
ret += (x + 1) * (x + 2) % MOD * c[i] % MOD
- (2 * x + 3) * cc[i] % MOD
+ ccc[i];
return ret % MOD * INV2 % MOD;
}
LL sum(LL l, LL r) { return sum(r) - sum(l - 1); }
}
- 三维
inline int lowbit(int x) { return x & -x; }
void update(int x, int y, int z, int d) {
for (int i = x; i <= n; i += lowbit(i))
for (int j = y; j <= n; j += lowbit(j))
for (int k = z; k <= n; k += lowbit(k))
c[i][j][k] += d;
}
LL query(int x, int y, int z) {
LL ret = 0;
for (int i = x; i > 0; i -= lowbit(i))
for (int j = y; j > 0; j -= lowbit(j))
for (int k = z; k > 0; k -= lowbit(k))
ret += c[i][j][k];
return ret;
}
LL solve(int x, int y, int z, int xx, int yy, int zz) {
return query(xx, yy, zz)
- query(xx, yy, z - 1)
- query(xx, y - 1, zz)
- query(x - 1, yy, zz)
+ query(xx, y - 1, z - 1)
+ query(x - 1, yy, z - 1)
+ query(x - 1, y - 1, zz)
- query(x - 1, y - 1, z - 1);
- 正常主席树
namespace tree {
#define mid ((l + r) >> 1)
#define lson l, mid
#define rson mid + 1, r
const int MAGIC = M * 30;
struct P {
int sum, ls, rs;
} tr[MAGIC] = {{0, 0, 0}};
int sz = 1;
int N(int sum, int ls, int rs) {
if (sz == MAGIC) assert(0);
tr[sz] = {sum, ls, rs};
return sz++;
}
int ins(int o, int x, int v, int l = 1, int r = ls) {
if (x < l || x > r) return o;
const P& t = tr[o];
if (l == r) return N(t.sum + v, 0, 0);
return N(t.sum + v, ins(t.ls, x, v, lson), ins(t.rs, x, v, rson));
}
int query(int o, int ql, int qr, int l = 1, int r = ls) {
if (ql > r || l > qr) return 0;
const P& t = tr[o];
if (ql <= l && r <= qr) return t.sum;
return query(t.ls, ql, qr, lson) + query(t.rs, ql, qr, rson);
}
}
- 第 k 大
struct TREE {
#define mid ((l + r) >> 1)
#define lson l, mid
#define rson mid + 1, r
struct P {
int w, ls, rs;
} tr[maxn * 20];
int sz = 1;
TREE() { tr[0] = {0, 0, 0}; }
int N(int w, int ls, int rs) {
tr[sz] = {w, ls, rs};
return sz++;
}
int ins(int tt, int l, int r, int x) {
if (x < l || r < x) return tt;
const P& t = tr[tt];
if (l == r) return N(t.w + 1, 0, 0);
return N(t.w + 1, ins(t.ls, lson, x), ins(t.rs, rson, x));
}
int query(int pp, int qq, int l, int r, int k) { // (pp, qq]
if (l == r) return l;
const P &p = tr[pp], &q = tr[qq];
int w = tr[q.ls].w - tr[p.ls].w;
if (k <= w) return query(p.ls, q.ls, lson, k);
else return query(p.rs, q.rs, rson, k - w);
}
} tree;
- 树状数组套主席树
typedef vector<int> VI;
struct TREE {
#define mid ((l + r) >> 1)
#define lson l, mid
#define rson mid + 1, r
struct P {
int w, ls, rs;
} tr[maxn * 20 * 20];
int sz = 1;
TREE() { tr[0] = {0, 0, 0}; }
int N(int w, int ls, int rs) {
tr[sz] = {w, ls, rs};
return sz++;
}
int add(int tt, int l, int r, int x, int d) {
if (x < l || r < x) return tt;
const P& t = tr[tt];
if (l == r) return N(t.w + d, 0, 0);
return N(t.w + d, add(t.ls, lson, x, d), add(t.rs, rson, x, d));
}
int ls_sum(const VI& rt) {
int ret = 0;
FOR (i, 0, rt.size())
ret += tr[tr[rt[i]].ls].w;
return ret;
}
inline void ls(VI& rt) { transform(rt.begin(), rt.end(), rt.begin(), [&](int x)->int{ return tr[x].ls; }); }
inline void rs(VI& rt) { transform(rt.begin(), rt.end(), rt.begin(), [&](int x)->int{ return tr[x].rs; }); }
int query(VI& p, VI& q, int l, int r, int k) {
if (l == r) return l;
int w = ls_sum(q) - ls_sum(p);
if (k <= w) {
ls(p); ls(q);
return query(p, q, lson, k);
}
else {
rs(p); rs(q);
return query(p, q, rson, k - w);
}
}
} tree;
struct BIT {
int root[maxn];
void init() { memset(root, 0, sizeof root); }
inline int lowbit(int x) { return x & -x; }
void update(int p, int x, int d) {
for (int i = p; i <= m; i += lowbit(i))
root[i] = tree.add(root[i], 1, m, x, d);
}
int query(int l, int r, int k) {
VI p, q;
for (int i = l - 1; i > 0; i -= lowbit(i)) p.push_back(root[i]);
for (int i = r; i > 0; i -= lowbit(i)) q.push_back(root[i]);
return tree.query(p, q, 1, m, k);
}
} bit;
void init() {
m = 10000;
tree.sz = 1;
bit.init();
FOR (i, 1, m + 1)
bit.update(i, a[i], 1);
}
namespace LTree {
extern struct P* null, *pit;
queue<P*> trash;
const int M = 1E5 + 100;
struct P {
P *ls, *rs;
LL v;
int d;
void operator delete (void* ptr) {
trash.push((P*)ptr);
}
void* operator new(size_t size) {
if (trash.empty()) return pit++;
void* ret = trash.front(); trash.pop(); return ret;
}
void prt() {
if (this == null) return;
cout << v << ' ';
ls->prt(); rs->prt();
}
} pool[M], *pit = pool, *null = new P{0, 0, -1, -1};
P* N(LL v) {
return new P{null, null, v, 0};
}
P* merge(P* a, P* b) {
if (a == null) return b;
if (b == null) return a;
if (a->v > b->v) swap(a, b);
a->rs = merge(a->rs, b);
if (a->ls->d < a->rs->d) swap(a->ls, a->rs);
a->d = a->rs->d + 1;
return a;
}
LL pop(P*& o) {
LL ret = o->v;
P* t = o;
o = merge(o->ls, o->rs);
delete t;
return ret;
}
}
可持久化
namespace LTree {
extern struct P* null, *pit;
queue<P*> trash;
const int M = 1E6 + 100;
struct P {
P *ls, *rs;
LL v;
int d;
void operator delete (void* ptr) {
trash.push((P*)ptr);
}
void* operator new(size_t size) {
if (trash.empty()) return pit++;
void* ret = trash.front(); trash.pop(); return ret;
}
} pool[M], *pit = pool, *null = new P{0, 0, -1, -1};
P* N(LL v, P* ls = null, P* rs = null) {
if (ls->d < rs->d) swap(ls, rs);
return new P{ls, rs, v, rs->d + 1};
}
P* merge(P* a, P* b) {
if (a == null) return b;
if (b == null) return a;
if (a->v < b->v)
return N(a->v, a->ls, merge(a->rs, b));
else
return N(b->v, b->ls, merge(b->rs, a));
}
LL pop(P*& o) {
LL ret = o->v;
o = merge(o->ls, o->rs);
return ret;
}
}
- 非旋 Treap
- v 小根堆
- 模板题 bzoj 3224
- lower 第一个大于等于的是第几个 (0-based)
- upper 第一个大于的是第几个 (0-based)
- split 左侧分割出 rk 个元素
- 树套树 略
namespace treap {
const int M = maxn * 17;
extern struct P* const null;
struct P {
P *ls, *rs;
int v, sz;
unsigned rd;
P(int v): ls(null), rs(null), v(v), sz(1), rd(rnd()) {}
P(): sz(0) {}
P* up() { sz = ls->sz + rs->sz + 1; return this; }
int lower(int v) {
if (this == null) return 0;
return this->v >= v ? ls->lower(v) : rs->lower(v) + ls->sz + 1;
}
int upper(int v) {
if (this == null) return 0;
return this->v > v ? ls->upper(v) : rs->upper(v) + ls->sz + 1;
}
} *const null = new P, pool[M], *pit = pool;
P* merge(P* l, P* r) {
if (l == null) return r; if (r == null) return l;
if (l->rd < r->rd) { l->rs = merge(l->rs, r); return l->up(); }
else { r->ls = merge(l, r->ls); return r->up(); }
}
void split(P* o, int rk, P*& l, P*& r) {
if (o == null) { l = r = null; return; }
if (o->ls->sz >= rk) { split(o->ls, rk, l, o->ls); r = o->up(); }
else { split(o->rs, rk - o->ls->sz - 1, o->rs, r); l = o->up(); }
}
}
- 持久化 Treap
namespace treap {
const int M = maxn * 17 * 12;
extern struct P* const null, *pit;
struct P {
P *ls, *rs;
int v, sz;
LL sum;
P(P* ls, P* rs, int v): ls(ls), rs(rs), v(v), sz(ls->sz + rs->sz + 1),
sum(ls->sum + rs->sum + v) {}
P() {}
void* operator new(size_t _) { return pit++; }
template<typename T>
int rk(int v, T&& cmp) {
if (this == null) return 0;
return cmp(this->v, v) ? ls->rk(v, cmp) : rs->rk(v, cmp) + ls->sz + 1;
}
int lower(int v) { return rk(v, greater_equal<int>()); }
int upper(int v) { return rk(v, greater<int>()); }
} pool[M], *pit = pool, *const null = new P;
P* merge(P* l, P* r) {
if (l == null) return r; if (r == null) return l;
if (rnd() % (l->sz + r->sz) < l->sz) return new P{l->ls, merge(l->rs, r), l->v};
else return new P{merge(l, r->ls), r->rs, r->v};
}
void split(P* o, int rk, P*& l, P*& r) {
if (o == null) { l = r = null; return; }
if (o->ls->sz >= rk) { split(o->ls, rk, l, r); r = new P{r, o->rs, o->v}; }
else { split(o->rs, rk - o->ls->sz - 1, l, r); l = new P{o->ls, l, o->v}; }
}
}
- 带 pushdown 的持久化 Treap
- 注意任何修改操作前一定要 FIX
int now;
namespace Treap {
const int M = 10000000;
extern struct P* const null, *pit;
struct P {
P *ls, *rs;
int sz, time;
LL cnt, sc, pos, add;
bool rev;
P* up() { sz = ls->sz + rs->sz + 1; sc = ls->sc + rs->sc + cnt; return this; } // MOD
P* check() {
if (time == now) return this;
P* t = new(pit++) P; *t = *this; t->time = now; return t;
};
P* _do_rev() { rev ^= 1; add *= -1; pos *= -1; swap(ls, rs); return this; } // MOD
P* _do_add(LL v) { add += v; pos += v; return this; } // MOD
P* do_rev() { if (this == null) return this; return check()->_do_rev(); } // FIX & MOD
P* do_add(LL v) { if (this == null) return this; return check()->_do_add(v); } // FIX & MOD
P* _down() { // MOD
if (rev) { ls = ls->do_rev(); rs = rs->do_rev(); rev = 0; }
if (add) { ls = ls->do_add(add); rs = rs->do_add(add); add = 0; }
return this;
}
P* down() { return check()->_down(); } // FIX & MOD
void _split(LL p, P*& l, P*& r) { // MOD
if (pos >= p) { ls->split(p, l, r); ls = r; r = up(); }
else { rs->split(p, l, r); rs = l; l = up(); }
}
void split(LL p, P*& l, P*& r) { // FIX & MOD
if (this == null) l = r = null;
else down()->_split(p, l, r);
}
} pool[M], *pit = pool, *const null = new P;
P* merge(P* a, P* b) {
if (a == null) return b; if (b == null) return a;
if (rand() % (a->sz + b->sz) < a->sz) { a = a->down(); a->rs = merge(a->rs, b); return a->up(); }
else { b = b->down(); b->ls = merge(a, b->ls); return b->up(); }
}
}
- 区间 ADD,SUM
namespace treap {
const int M = 8E5 + 100;
extern struct P*const null;
struct P {
P *ls, *rs;
int sz, val, add, sum;
P(int v, P* ls = null, P* rs = null): ls(ls), rs(rs), sz(1), val(v), add(0), sum(v) {}
P(): sz(0), val(0), add(0), sum(0) {}
P* up() {
assert(this != null);
sz = ls->sz + rs->sz + 1;
sum = ls->sum + rs->sum + val + add * sz;
return this;
}
void upd(int v) {
if (this == null) return;
add += v;
sum += sz * v;
}
P* down() {
if (add) {
ls->upd(add); rs->upd(add);
val += add;
add = 0;
}
return this;
}
P* select(int rk) {
if (rk == ls->sz + 1) return this;
return ls->sz >= rk ? ls->select(rk) : rs->select(rk - ls->sz - 1);
}
} pool[M], *pit = pool, *const null = new P, *rt = null;
P* merge(P* a, P* b) {
if (a == null) return b->up();
if (b == null) return a->up();
if (rand() % (a->sz + b->sz) < a->sz) {
a->down()->rs = merge(a->rs, b);
return a->up();
} else {
b->down()->ls = merge(a, b->ls);
return b->up();
}
}
void split(P* o, int rk, P*& l, P*& r) {
if (o == null) { l = r = null; return; }
o->down();
if (o->ls->sz >= rk) {
split(o->ls, rk, l, o->ls);
r = o->up();
} else {
split(o->rs, rk - o->ls->sz - 1, o->rs, r);
l = o->up();
}
}
inline void insert(int k, int v) {
P *l, *r;
split(rt, k - 1, l, r);
rt = merge(merge(l, new (pit++) P(v)), r);
}
inline void erase(int k) {
P *l, *r, *_, *t;
split(rt, k - 1, l, t);
split(t, 1, _, r);
rt = merge(l, r);
}
P* build(int l, int r, int* a) {
if (l > r) return null;
if (l == r) return new(pit++) P(a[l]);
int m = (l + r) / 2;
return (new(pit++) P(a[m], build(l, m - 1, a), build(m + 1, r, a)))->up();
}
};
- 区间 REVERSE,ADD,MIN
namespace treap {
extern struct P*const null;
struct P {
P *ls, *rs;
int sz, v, add, m;
bool flip;
P(int v, P* ls = null, P* rs = null): ls(ls), rs(rs), sz(1), v(v), add(0), m(v), flip(0) {}
P(): sz(0), v(INF), m(INF) {}
void upd(int v) {
if (this == null) return;
add += v; m += v;
}
void rev() {
if (this == null) return;
swap(ls, rs);
flip ^= 1;
}
P* up() {
assert(this != null);
sz = ls->sz + rs->sz + 1;
m = min(min(ls->m, rs->m), v) + add;
return this;
}
P* down() {
if (add) {
ls->upd(add); rs->upd(add);
v += add;
add = 0;
}
if (flip) {
ls->rev(); rs->rev();
flip = 0;
}
return this;
}
P* select(int k) {
if (ls->sz + 1 == k) return this;
if (ls->sz >= k) return ls->select(k);
return rs->select(k - ls->sz - 1);
}
} pool[M], *const null = new P, *pit = pool, *rt = null;
P* merge(P* a, P* b) {
if (a == null) return b;
if (b == null) return a;
if (rnd() % (a->sz + b->sz) < a->sz) {
a->down()->rs = merge(a->rs, b);
return a->up();
} else {
b->down()->ls = merge(a, b->ls);
return b->up();
}
}
void split(P* o, int k, P*& l, P*& r) {
if (o == null) { l = r = null; return; }
o->down();
if (o->ls->sz >= k) {
split(o->ls, k, l, o->ls);
r = o->up();
} else {
split(o->rs, k - o->ls->sz - 1, o->rs, r);
l = o->up();
}
}
P* build(int l, int r, int* v) {
if (l > r) return null;
int m = (l + r) >> 1;
return (new (pit++) P(v[m], build(l, m - 1, v), build(m + 1, r, v)))->up();
}
void go(int x, int y, void f(P*&)) {
P *l, *m, *r;
split(rt, y, l, r);
split(l, x - 1, l, m);
f(m);
rt = merge(merge(l, m), r);
}
}
using namespace treap;
int a[maxn], n, x, y, Q, v, k, d;
char s[100];
int main() {
cin >> n;
FOR (i, 1, n + 1) scanf("%d", &a[i]);
rt = build(1, n, a);
cin >> Q;
while (Q--) {
scanf("%s", s);
if (s[0] == 'A') {
scanf("%d%d%d", &x, &y, &v);
go(x, y, [](P*& o){ o->upd(v); });
} else if (s[0] == 'R' && s[3] == 'E') {
scanf("%d%d", &x, &y);
go(x, y, [](P*& o){ o->rev(); });
} else if (s[0] == 'R' && s[3] == 'O') {
scanf("%d%d%d", &x, &y, &d);
d %= y - x + 1;
go(x, y, [](P*& o){
P *l, *r;
split(o, o->sz - d, l, r);
o = merge(r, l);
});
} else if (s[0] == 'I') {
scanf("%d%d", &k, &v);
go(k + 1, k, [](P*& o){ o = new (pit++) P(v); });
} else if (s[0] == 'D') {
scanf("%d", &k);
go(k, k, [](P*& o){ o = null; });
} else if (s[0] == 'M') {
scanf("%d%d", &x, &y);
go(x, y, [](P*& o) {
printf("%d\n", o->m);
});
}
}
}
- 持久化
namespace treap {
struct P;
extern P*const null;
P* N(P* ls, P* rs, LL v, bool fill);
struct P {
P *const ls, *const rs;
const int sz, v;
const LL sum;
bool fill;
int cnt;
void split(int k, P*& l, P*& r) {
if (this == null) { l = r = null; return; }
if (ls->sz >= k) {
ls->split(k, l, r);
r = N(r, rs, v, fill);
} else {
rs->split(k - ls->sz - fill, l, r);
l = N(ls, l, v, fill);
}
}
} *const null = new P{0, 0, 0, 0, 0, 0, 1};
P* N(P* ls, P* rs, LL v, bool fill) {
ls->cnt++; rs->cnt++;
return new P{ls, rs, ls->sz + rs->sz + fill, v, ls->sum + rs->sum + v, fill, 1};
}
P* merge(P* a, P* b) {
if (a == null) return b;
if (b == null) return a;
if (rand() % (a->sz + b->sz) < a->sz)
return N(a->ls, merge(a->rs, b), a->v, a->fill);
else
return N(merge(a, b->ls), b->rs, b->v, b->fill);
}
void go(P* o, int x, int y, P*& l, P*& m, P*& r) {
o->split(y, l, r);
l->split(x - 1, l, m);
}
}
- 注意这个不是可持久化并查集
- 查找时不进行路径压缩
- 复杂度靠按秩合并解决
namespace uf {
int fa[maxn], sz[maxn];
int undo[maxn], top;
void init() { memset(fa, -1, sizeof fa); memset(sz, 0, sizeof sz); top = 0; }
int findset(int x) { while (fa[x] != -1) x = fa[x]; return x; }
bool join(int x, int y) {
x = findset(x); y = findset(y);
if (x == y) return false;
if (sz[x] > sz[y]) swap(x, y);
undo[top++] = x;
fa[x] = y;
sz[y] += sz[x] + 1;
return true;
}
inline int checkpoint() { return top; }
void rewind(int t) {
while (top > t) {
int x = undo[--top];
sz[fa[x]] -= sz[x] + 1;
fa[x] = -1;
}
}
}
-
注意 link 的 y 的范围是 [1, n]
-
注意在某些情况下替换掉 memset
-
精确覆盖
struct P {
P *L, *R, *U, *D;
int x, y;
};
const int INF = 1E9;
struct DLX {
#define TR(i, D, s) for (P* i = s->D; i != s; i = i->D)
static const int M = 2E5;
P pool[M], *h[M], *r[M], *pit;
int sz[M];
bool solved;
stack<int> ans;
void init(int n) {
pit = pool;
++n;
solved = false;
while (!ans.empty()) ans.pop();
memset(r, 0, sizeof r);
memset(sz, 0, sizeof sz);
FOR (i, 0, n)
h[i] = new (pit++) P;
FOR (i, 0, n) {
h[i]->L = h[(i + n - 1) % n];
h[i]->R = h[(i + 1) % n];
h[i]->U = h[i]->D = h[i];
h[i]->y = i;
}
}
void link(int x, int y) {
sz[y]++;
auto p = new (pit++) P;
p->x = x; p->y = y;
p->U = h[y]->U; p->D = h[y];
p->D->U = p->U->D = p;
if (!r[x]) r[x] = p->L = p->R = p;
else {
p->L = r[x]; p->R = r[x]->R;
p->L->R = p->R->L = p;
}
}
void remove(P* p) {
p->L->R = p->R; p->R->L = p->L;
TR (i, D, p)
TR (j, R, i) {
j->D->U = j->U; j->U->D = j->D;
sz[j->y]--;
}
}
void recall(P* p) {
p->L->R = p->R->L = p;
TR (i, U, p)
TR (j, L, i) {
j->D->U = j->U->D = j;
sz[j->y]++;
}
}
bool dfs(int d) {
if (solved) return true;
if (h[0]->R == h[0]) return solved = true;
int m = INF;
P* c;
TR (i, R, h[0])
if (sz[i->y] < m) { m = sz[i->y]; c = i; }
remove(c);
TR (i, D, c) {
ans.push(i->x);
TR (j, R, i) remove(h[j->y]);
if (dfs(d + 1)) return true;
TR (j, L, i) recall(h[j->y]);
ans.pop();
}
recall(c);
return false;
}
} dlx;
- 可重复覆盖
struct P {
P *L, *R, *U, *D;
int x, y;
};
const int INF = 1E9;
struct DLX {
#define TR(i, D, s) for (P* i = s->D; i != s; i = i->D)
static const int M = 2E5;
P pool[M], *h[M], *r[M], *pit;
int sz[M], vis[M], ans, clk;
void init(int n) {
clk = 0;
ans = INF;
pit = pool;
++n;
memset(r, 0, sizeof r);
memset(sz, 0, sizeof sz);
memset(vis, -1, sizeof vis);
FOR (i, 0, n)
h[i] = new (pit++) P;
FOR (i, 0, n) {
h[i]->L = h[(i + n - 1) % n];
h[i]->R = h[(i + 1) % n];
h[i]->U = h[i]->D = h[i];
h[i]->y = i;
}
}
void link(int x, int y) {
sz[y]++;
auto p = new (pit++) P;
p->x = x; p->y = y;
p->U = h[y]->U; p->D = h[y];
p->D->U = p->U->D = p;
if (!r[x]) r[x] = p->L = p->R = p;
else {
p->L = r[x]; p->R = r[x]->R;
p->L->R = p->R->L = p;
}
}
void remove(P* p) {
TR (i, D, p) {
i->L->R = i->R;
i->R->L = i->L;
}
}
void recall(P* p) {
TR (i, U, p)
i->L->R = i->R->L = i;
}
int eval() {
++clk;
int ret = 0;
TR (i, R, h[0])
if (vis[i->y] != clk) {
++ret;
vis[i->y] = clk;
TR (j, D, i)
TR (k, R, j)
vis[k->y] = clk;
}
return ret;
}
void dfs(int d) {
if (h[0]->R == h[0]) { ans = min(ans, d); return; }
if (eval() + d >= ans) return;
P* c;
int m = INF;
TR (i, R, h[0])
if (sz[i->y] < m) { m = sz[i->y]; c = i; }
TR (i, D, c) {
remove(i);
TR (j, R, i) remove(j);
dfs(d + 1);
TR (j, L, i) recall(j);
recall(i);
}
}
} dlx;
const int maxn = 2E5 + 100;
struct P {
int x, y;
int* f;
bool d1, d2;
} a[maxn], b[maxn], c[maxn];
int f[maxn];
void go2(int l, int r) {
if (l + 1 == r) return;
int m = (l + r) >> 1;
go2(l, m); go2(m, r);
FOR (i, l, m) b[i].d2 = 0;
FOR (i, m, r) b[i].d2 = 1;
merge(b + l, b + m, b + m, b + r, c + l, [](const P& a, const P& b)->bool {
if (a.y != b.y) return a.y < b.y;
return a.d2 > b.d2;
});
int mx = -1;
FOR (i, l, r) {
if (c[i].d1 && c[i].d2) *c[i].f = max(*c[i].f, mx + 1);
if (!c[i].d1 && !c[i].d2) mx = max(mx, *c[i].f);
}
FOR (i, l, r) b[i] = c[i];
}
void go1(int l, int r) { // [l, r)
if (l + 1 == r) return;
int m = (l + r) >> 1;
go1(l, m);
FOR (i, l, m) a[i].d1 = 0;
FOR (i, m, r) a[i].d1 = 1;
copy(a + l, a + r, b + l);
sort(b + l, b + r, [](const P& a, const P& b)->bool {
if (a.x != b.x) return a.x < b.x;
return a.d1 > b.d1;
});
go2(l, r);
go1(m, r);
}
- k 维 LIS
struct P {
int v[K];
LL f;
bool d[K];
} o[N << 10];
P* a[K][N << 10];
int k;
void go(int now, int l, int r) {
if (now == 0) {
if (l + 1 == r) return;
int m = (l + r) / 2;
go(now, l, m);
FOR (i, l, m) a[now][i]->d[now] = 0;
FOR (i, m, r) a[now][i]->d[now] = 1;
copy(a[now] + l, a[now] + r, a[now + 1] + l);
sort(a[now + 1] + l, a[now + 1] + r, [now](const P* a, const P* b){
if (a->v[now] != b->v[now]) return a->v[now] < b->v[now];
return a->d[now] > b->d[now];
});
go(now + 1, l, r);
go(now, m, r);
} else {
if (l + 1 == r) return;
int m = (l + r) / 2;
go(now, l, m); go(now, m, r);
FOR (i, l, m) a[now][i]->d[now] = 0;
FOR (i, m, r) a[now][i]->d[now] = 1;
merge(a[now] + l, a[now] + m, a[now] + m, a[now] + r, a[now + 1] + l, [now](const P* a, const P* b){
if (a->v[now] != b->v[now]) return a->v[now] < b->v[now];
return a->d[now] > b->d[now];
});
copy(a[now + 1] + l, a[now + 1] + r, a[now] + l);
if (now < k - 2) {
go(now + 1, l, r);
} else {
LL sum = 0;
FOR (i, l, r) {
dbg(a[now][i]->v[0], a[now][i]->v[1], a[now][i]->f,
a[now][i]->d[0], a[now][i]->d[1]);
int cnt = 0;
FOR (j, 0, now + 1) cnt += a[now][i]->d[j];
if (cnt == 0) {
sum += a[now][i]->f;
} else if (cnt == now + 1) {
a[now][i]->f = (a[now][i]->f + sum) % MOD;
}
}
}
}
}
void build(const vector<int>& a) {
static P *stack[M], *x, *last;
int p = 0;
FOR (i, 0, a.size()) {
x = new P(i + 1, a[i]);
last = null;
while (p && stack[p - 1]->v > x->v) {
stack[p - 1]->maintain();
last = stack[--p];
}
if (p) stack[p - 1]->rs = x;
x->ls = last;
stack[p++] = x;
}
while (p)
stack[--p]->maintain();
rt = stack[0];
}
void build() {
static int s[N], last;
int p = 0;
FOR (x, 1, n + 1) {
last = 0;
while (p && val[s[p - 1]] > val[x]) last = s[--p];
if (p) G[s[p - 1]][1] = x;
if (last) G[x][0] = last;
s[p++] = x;
}
rt = s[0];
}
- 二进制 Trie
namespace trie {
const int M = 31;
int ch[N * M][2], sz;
void init() { memset(ch, 0, sizeof ch); sz = 2; }
void ins(LL x) {
int u = 1;
FORD (i, M, -1) {
bool b = x & (1LL << i);
if (!ch[u][b]) ch[u][b] = sz++;
u = ch[u][b];
}
}
}
- 持久化二进制 Trie
sz=1
struct P { int w, ls, rs; };
P tr[M] = {{0, 0, 0}};
int sz;
int _new(int w, int ls, int rs) { tr[sz] = {w, ls, rs}; return sz++; }
int ins(int oo, int v, int d = 30) {
P& o = tr[oo];
if (d == -1) return _new(o.w + 1, 0, 0);
bool u = v & (1 << d);
return _new(o.w + 1, u == 0 ? ins(o.ls, v, d - 1) : o.ls, u == 1 ? ins(o.rs, v, d - 1) : o.rs);
}
int query(int pp, int qq, int v, int d = 30) {
if (d == -1) return 0;
bool u = v & (1 << d);
P &p = tr[pp], &q = tr[qq];
int lw = tr[q.ls].w - tr[p.ls].w;
int rw = tr[q.rs].w - tr[p.rs].w;
int ret = 0;
if (u == 0) {
if (rw) { ret += 1 << d; ret += query(p.rs, q.rs, v, d - 1); }
else ret += query(p.ls, q.ls, v, d - 1);
} else {
if (lw) { ret += 1 << d; ret += query(p.ls, q.ls, v, d - 1); }
else ret += query(p.rs, q.rs, v, d - 1);
}
return ret;
}
- binary_heap_tag
- pairing_heap_tag 支持修改
- thin_heap_tag 如果修改只有 increase 则较快,不支持 join
#include<ext/pb_ds/priority_queue.hpp>
using namespace __gnu_pbds;
typedef __gnu_pbds::priority_queue<LL, less<LL>, pairing_heap_tag> PQ;
__gnu_pbds::priority_queue<int, cmp, pairing_heap_tag>::point_iterator it;
PQ pq, pq2;
int main() {
auto it = pq.push(2);
pq.push(3);
assert(pq.top() == 3);
pq.modify(it, 4);
assert(pq.top() == 4);
pq2.push(5);
pq.join(pq2);
assert(pq.top() == 5);
}
-
ov_tree_tag
-
rb_tree_tag
-
splay_tree_tag
-
mapped: null_type 或 null_mapped_type(旧版本) 为空
-
Node_Update 为 tree_order_statistics_node_update 时才可以 find_by_order & order_of_key
-
find_by_order 找 order + 1 小的元素 (其实都是从 0 开始计数),或者有 order 个元素比它小的 key
-
order_of_key 有多少个比 r_key 小的元素
-
join & split
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
using Tree = tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update>;
Tree t;
#include <ext/rope>
using namespace __gnu_cxx;
rope<int> s;
int main() {
FOR (i, 0, 5) s.push_back(i); // 0 1 2 3 4
s.replace(1, 2, s); // 0 (0 1 2 3 4) 3 4
auto ss = s.substr(2, 2); // 1 2、
s.erase(2, 2); // 0 1 4
s.insert(2, s); // equal to s.replace(2, 0, s)
assert(s[2] == s.at(2)); // 2
}
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
using namespace __gnu_pbds;
gp_hash_table<int, int> mp;
cc_hash_table<int, int> mp;
- 图中相邻的结点在伸展树中不一定是父子关系
- 遇事不决
make_root
- 跑左右儿子的时候不要忘记
down
namespace lct {
extern struct P *const null;
const int M = N;
struct P {
P *fa, *ls, *rs;
int v, maxv;
bool rev;
bool has_fa() { return fa->ls == this || fa->rs == this; }
bool d() { return fa->ls == this; }
P*& c(bool x) { return x ? ls : rs; }
void do_rev() {
if (this == null) return;
rev ^= 1;
swap(ls, rs);
}
P* up() {
maxv = max(v, max(ls->maxv, rs->maxv));
return this;
}
void down() {
if (rev) {
rev = 0;
ls->do_rev(); rs->do_rev();
}
}
void all_down() { if (has_fa()) fa->all_down(); down(); }
} *const null = new P{0, 0, 0, 0, 0, 0}, pool[M], *pit = pool;
void rot(P* o) {
bool dd = o->d();
P *f = o->fa, *t = o->c(!dd);
if (f->has_fa()) f->fa->c(f->d()) = o; o->fa = f->fa;
if (t != null) t->fa = f; f->c(dd) = t;
o->c(!dd) = f->up(); f->fa = o;
}
void splay(P* o) {
o->all_down();
while (o->has_fa()) {
if (o->fa->has_fa())
rot(o->d() ^ o->fa->d() ? o : o->fa);
rot(o);
}
o->up();
}
void access(P* u, P* v = null) {
if (u == null) return;
splay(u); u->rs = v;
access(u->up()->fa, u);
}
void make_root(P* o) {
access(o); splay(o); o->do_rev();
}
void split(P* o, P* u) {
make_root(o); access(u); splay(u);
}
void link(P* u, P* v) {
make_root(u); u->fa = v;
}
void cut(P* u, P* v) {
split(u, v);
u->fa = v->ls = null; v->up();
}
bool adj(P* u, P* v) {
split(u, v);
return v->ls == u && u->ls == null && u->rs == null;
}
bool linked(P* u, P* v) {
split(u, v);
return u == v || u->fa != null;
}
P* findrt(P* o) {
access(o); splay(o);
while (o->ls != null) o = o->ls;
return o;
}
P* findfa(P* rt, P* u) {
split(rt, u);
u = u->ls;
while (u->rs != null) {
u = u->rs;
u->down();
}
return u;
}
}
- 维护子树大小
P* up() {
sz = ls->sz + rs->sz + _sz + 1;
return this;
}
void access(P* u, P* v = null) {
if (u == null) return;
splay(u);
u->_sz += u->rs->sz - v->sz;
u->rs = v;
access(u->up()->fa, u);
}
void link(P* u, P* v) {
split(u, v);
u->fa = v; v->_sz += u->sz;
v->up();
}
- [l, r)
while (l > q.l) mv(--l, 1);
while (r < q.r) mv(r++, 1);
while (l < q.l) mv(l++, -1);
while (r > q.r) mv(--r, -1);
- 树上莫队
- 注意初始状态 u = v = 1, flip(1)
struct Q {
int u, v, idx;
bool operator < (const Q& b) const {
const Q& a = *this;
return blk[a.u] < blk[b.u] || (blk[a.u] == blk[b.u] && in[a.v] < in[b.v]);
}
};
void dfs(int u = 1, int d = 0) {
static int S[maxn], sz = 0, blk_cnt = 0, clk = 0;
in[u] = clk++;
dep[u] = d;
int btm = sz;
for (int v: G[u]) {
if (v == fa[u]) continue;
fa[v] = u;
dfs(v, d + 1);
if (sz - btm >= B) {
while (sz > btm) blk[S[--sz]] = blk_cnt;
++blk_cnt;
}
}
S[sz++] = u;
if (u == 1) while (sz) blk[S[--sz]] = blk_cnt - 1;
}
void flip(int k) {
dbg(k);
if (vis[k]) {
// ...
} else {
// ...
}
vis[k] ^= 1;
}
void go(int& k) {
if (bug == -1) {
if (vis[k] && !vis[fa[k]]) bug = k;
if (!vis[k] && vis[fa[k]]) bug = fa[k];
}
flip(k);
k = fa[k];
}
void mv(int a, int b) {
bug = -1;
if (vis[b]) bug = b;
if (dep[a] < dep[b]) swap(a, b);
while (dep[a] > dep[b]) go(a);
while (a != b) {
go(a); go(b);
}
go(a); go(bug);
}
for (Q& q: query) {
mv(u, q.u); u = q.u;
mv(v, q.v); v = q.v;
ans[q.idx] = Ans;
}