树套树

树套树是一种思想,一般来说是一棵树套着另外一棵树。

例如线段树里面每一个点都是一棵平衡树就算是树套树。

外层的树有很多种情况,一般来说是线段树或树状数组,有时是平衡树。

内层的树比较常见的是平衡树或者线段树,甚至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;
}

P3332 [ZJOI2013] K大数查询

posted @ 2025-02-13 10:32  Helioca  阅读(26)  评论(0)    收藏  举报
Document