树套树
树套树是一种思想,一般来说是一棵树套着另外一棵树。
例如线段树里面每一个点都是一棵平衡树就算是树套树。
外层的树有很多种情况,一般来说是线段树或树状数组,有时是平衡树。
内层的树比较常见的是平衡树或者线段树,甚至STL也可以。
树套树-简单版
查询操作需要问我们某个区间小于x的最大的数。如果是一整个区间的话,直接用lower_bound就可以了。
[l,r]的限制,需要在外面套用一棵线段树。在每一个点里面存一个set,存储的是线段树区间里面的所有数,时间复杂度是\(O(nlogn)\)的,查询的时间是\(O(nlog^2n)\)。
#include <bits/stdc++.h>
using namespace std;
const int N = 50005, inf = 0x3f3f3f3f;
int n, m, a[N];
multiset<int> s[N << 2];
void build_tree(int p, int l, int r)
{
for (int i = l; i <= r; ++ i) s[p].insert(a[i]);
s[p].insert(-inf), s[p].insert(inf);
if(l == r) return ;
int mid = l + r >> 1;
build_tree(p << 1, l, mid), build_tree(p << 1 | 1, mid + 1, r);
return ;
}
void update(int p, int l, int r, int x, int w)
{
s[p].erase(s[p].find(a[x]));
s[p].insert(w);
if(l == r) return ;
int mid = l + r >> 1;
if(x <= mid) update(p << 1, l, mid, x, w);
else update(p << 1 | 1, mid + 1, r, x, w);
return ;
}
int query(int p, int l, int r, int L, int R, int x)
{
if(L <= l && r <= R)
{
set<int> :: iterator it = s[p].upper_bound(x - 1);
-- it;
return *it;
}
if(l > R || r < L) return -inf;
int mid = l + r >> 1;
return max(query(p << 1, l, mid, L, R, x), query(p << 1 | 1, mid + 1, r, L, R, x));
}
int main()
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
build_tree(1, 1, n);
for (int i = 1; i <= m; ++ i)
{
int opt, l, r, x;
scanf("%d %d %d", &opt, &l, &r);
if(opt == 1)
{
update(1, 1, n, l, r);
a[l] = r;
}
else
{
scanf("%d", &x);
printf("%d\n", query(1, 1, n, l, r, x));
}
}
return 0;
}
树套树
外层是线段树。
由于里面涉及到排名,所以不能用pbds,只能手写一个平衡树,支持siz的操作。
排名第k位的数无法通过合并每个小区间中的平衡树来求解,但是可以转化为二分来求。
好恶心/
【模板】树套树
#include <bits/stdc++.h>
using namespace std;
const int N = 50005, inf = 2147483647, M = N * 19 * 2;
int n, m, a[N], T[N << 2], cnt = 0;
struct spl
{
int v, p, siz, son[2];
void init(int _v, int _p)
{
v = _v, p = _p, siz = 1, son[0] = son[1] = 0;
return ;
}
}tr[M];
void push_up(int p)
{
tr[p].siz = tr[tr[p].son[0]].siz + tr[tr[p].son[1]].siz + 1;
return ;
}
void rotate(int x)
{
int y = tr[x].p, z = tr[y].p;
int k = (x == tr[y].son[1]);
tr[z].son[y == tr[z].son[1]] = x, tr[x].p = z;
tr[y].son[k] = tr[x].son[k ^ 1];
if(tr[x].son[k ^ 1]) tr[tr[x].son[k ^ 1]].p = y;
tr[x].son[k ^ 1] = y;
if(y) tr[y].p = x;
push_up(y), push_up(x);
return ;
}
void splay(int &rt, int x, int k)
{
while(tr[x].p != k)
{
int y = tr[x].p, z = tr[y].p;
if(z != k)
{
if((x == tr[y].son[0]) ^ (y == tr[z].son[0])) rotate(x);
else rotate(y);
}
rotate(x);
}
if(k == 0) rt = x;
return ;
}
void insert(int &rt, int w)
{
int u = rt, p = 0;
while(u) p = u, u = tr[u].son[w > tr[u].v];
u = ++ cnt;
tr[u].init(w, p);
if(p) tr[p].son[w > tr[p].v] = u;
splay(rt, u, 0);
return ;
}
void build_tree(int p, int l, int r)
{
for (int i = l; i <= r; ++ i) insert(T[p], a[i]);
insert(T[p], -inf), insert(T[p], inf);
if(l == r) return ;
int mid = l + r >> 1;
build_tree(p << 1, l, mid), build_tree(p << 1 | 1, mid + 1, r);
return ;
}
void change(int p, int l, int r, int x, int k)
{
int u = T[p], v;
while(u)
{
if(tr[u].v == a[x]) break;
if(a[x] > tr[u].v) u = tr[u].son[1];
else u = tr[u].son[0];
}
splay(T[p], u, 0);
v = tr[u].son[1], u = tr[u].son[0];
while(tr[u].son[1]) u = tr[u].son[1];
while(tr[v].son[0]) v = tr[v].son[0];
splay(T[p], u, 0);
splay(T[p], v, u);
tr[v].son[0] = 0;
push_up(v), push_up(u);
insert(T[p], k);
if(l == r) return ;
int mid = l + r >> 1;
if(x <= mid) change(p << 1, l, mid, x, k);
else change(p << 1 | 1, mid + 1, r, x, k);
return ;
}
int get_sum(int rt, int w)
{
int u = rt, sum = 0;
while(u)
{
if(w > tr[u].v) sum += tr[tr[u].son[0]].siz + 1, u = tr[u].son[1];
else u = tr[u].son[0];
}
return sum - 1;
}
int query(int p, int l, int r, int L, int R, int w)
{
if(L <= l && r <= R) return get_sum(T[p], w);
if(l > R || r < L) return 0;
int mid = l + r >> 1;
return query(p << 1, l, mid, L, R, w) + query(p << 1 | 1, mid + 1, r, L, R, w);
}
int get_pre(int rt, int k)
{
int u = rt, ans = -inf;
while(u)
{
if(k > tr[u].v) ans = max(ans, tr[u].v), u = tr[u].son[1];
else u = tr[u].son[0];
}
return ans;
}
int get_suc(int rt, int k)
{
int u = rt, ans = inf;
while(u)
{
if(k >= tr[u].v) u = tr[u].son[1];
else ans = min(ans, tr[u].v), u = tr[u].son[0];
}
return ans;
}
int query_pre(int p, int l, int r, int L, int R, int k)
{
if(L <= l && r <= R) return get_pre(T[p], k);
if(l > R || r < L) return -inf;
int mid = l + r >> 1;
return max(query_pre(p << 1, l, mid, L, R, k), query_pre(p << 1 | 1, mid + 1, r, L, R, k));
}
int query_suc(int p, int l, int r, int L, int R, int k)
{
if(L <= l && r <= R) return get_suc(T[p], k);
if(l > R || r < L) return inf;
int mid = l + r >> 1;
return min(query_suc(p << 1, l, mid, L, R, k), query_suc(p << 1 | 1, mid + 1, r, L, R, k));
}
int main()
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
build_tree(1, 1, n);
int opt, l, r, k, pos;
for (int i = 1; i <= m; ++ i)
{
scanf("%d", &opt);
if(opt == 1)
{
scanf("%d %d %d", &l, &r, &k);
printf("%d\n", query(1, 1, n, l, r, k) + 1);
}
else if(opt == 2)
{
scanf("%d %d %d", &l, &r, &k);
int L = 0, R = 100000000;
while(L <= R)
{
int mid = L + R >> 1;
if(query(1, 1, n, l, r, mid) + 1 <= k) pos = mid, L = mid + 1;
else R = mid - 1;
}
printf("%d\n", pos);
}
else if(opt == 3)
{
scanf("%d %d", &pos, &k);
change(1, 1, n, pos, k);
a[pos] = k;
}
else if(opt == 4)
{
scanf("%d %d %d", &l, &r, &k);
printf("%d\n", query_pre(1, 1, n, l, r, k));
}
else
{
scanf("%d %d %d", &l, &r, &k);
printf("%d\n", query_suc(1, 1, n, l, r, k));
}
}
return 0;
}

浙公网安备 33010602011771号