Chairman tree (persistent segment tree)

foreword

It 's really not purposeful to learn the chairman tree... ( It's really because it's too high -level )

"About the fact that I have been reading the chapter of <Advanced Guide> Persistent Data Structure and then I have learned about the chairman tree"

Therefore, learning a new data structure only requires a whole section of late revision.

Chairman tree

Also called persistent segment tree , functional segment tree. Its idea and persistence T rie \mathtt{Trie}Trie is similar . _

In fact, on the basis of the ordinary line segment tree, the update \mathtt{update} is modified.The up d a te operation makes it a persistent data structure :

Each time a new root node is created, the state after this modification is saved. When traversing the segment tree, create a copy of the changed part, and then directly point the child pointer to the unchanged part in the previous state.

The following figure shows the pair [ 4 , 4 ] [4,4][4,4 ] The state of the tree after modification.

(Note: The picture is from this Chairman Tree Blog )

However, the chair tree cannot support most range modifications. The reason is that the markup is difficult to download (there are several trees that depend on this subtree later). In some special problems, you can use tag permanent instead of tag download, for example: SP11470 TTM - To the moon .

Division of Array Subscripts

P3919 [Template] Persistent Segment Tree 1 (Persistent Array)

Essentially, a persistent array is implemented with a segment tree.

#include<bits/stdc++.h>
using namespace std;

#define rep(i, a, b) for(int i = a; i <= b; ++i)
const int maxn = 1e6 + 5;
int n, m;
int a[maxn], rt[maxn];
struct node{
    
    
	int l, r;
	int val;
}t[maxn << 5];
int tot;

inline int build(int nw, int l, int r)
{
    
    
	nw = ++tot;
	if(l == r)
	{
    
    
		t[nw].val = a[l];
		return nw;
	}
	int mid = (l + r) >> 1;
	t[nw].l = build(t[nw].l, l, mid);
	t[nw].r = build(t[nw].r, mid + 1, r);
	return nw;
}

inline int cpy(int x)
{
    
    
	int nw = ++tot;
	t[nw] = t[x];
	return nw;
}

inline int update(int lst, int l, int r, int k, int d)
{
    
    
	int nw = cpy(lst), mid = (l + r) >> 1;
	if(l == r)
		t[nw].val = d;
	else
	{
    
    
		if(k <= mid)
			t[nw].l = update(t[nw].l, l, mid, k, d);
		else t[nw].r = update(t[nw].r, mid + 1, r, k, d);
	}
	return nw;
}

inline int query(int nw, int l, int r, int k)
{
    
    
	if(l == r)
		return t[nw].val;
	else
	{
    
    
		int mid = (l + r) >> 1;
		if(k <= mid)
			return query(t[nw].l, l, mid, k);
		else return query(t[nw].r, mid + 1, r, k);
	}
}

int main()
{
    
    
	scanf("%d%d", &n, &m);
	rep(i, 1, n) scanf("%d", &a[i]);
	rt[0] = build(531, 1, n);
	rep(i, 1, m)
	{
    
    
		int v, opt, loc, d;
		scanf("%d%d%d", &v, &opt, &loc);
		if(opt == 1)
		{
    
    
			scanf("%d", &d);
			rt[i] = update(rt[v], 1, n, loc, d);
		}
		else
			printf("%d\n", query(rt[v], 1, n, loc)),
			rt[i] = rt[v];
	}
	return 0;
}

Divide the range

P3834 [Template] Persistent Segment Tree 2

discretize, then for each root node rooti root_irooti, which maintains the array from a 1 to a_1a1To ai a_iaiThe number of occurrences of each number in .

The time complexity of this algorithm is O ( ( N + M ) log N ) O((N+M)logN)O ( ( Women )+M ) l o g N ) , space complexityO ( N log N ) O(NlogN)O ( N l o g N )

#include<bits/stdc++.h>
using namespace std;

#define rep(i, a, b) for(int i = a; i <= b; ++i)
const int maxn = 2e5 + 5;
int n, m;
struct node{
    
    
	int ls, rs;
	int sum;
}t[maxn << 5];
int a[maxn], b[maxn];
int q;
int dt, tot;
int rt[maxn];

inline void build(int &nw, int l, int r)
{
    
    
	nw = ++tot;
	if(l == r) return;
	int mid = (l + r) >> 1;
	build(t[nw].ls, l, mid), build(t[nw].rs, mid + 1, r);
}

inline int addt(int lst, int l, int r)
{
    
    
	int nw = ++tot;
	t[nw] = t[lst], t[nw].sum += 1;
	if(l == r) return nw;
	int mid = (l + r) >> 1; 
	if(dt <= mid) t[nw].ls = addt(t[nw].ls, l, mid);
	else t[nw].rs = addt(t[nw].rs, mid + 1, r);
	return nw;
}

inline int query(int pl, int pr, int l, int r, int k)
{
    
    
	if(l == r) return l;
	int mid = (l + r) >> 1, lcnt = t[t[pr].ls].sum - t[t[pl].ls].sum;
	if(k <= lcnt)	
		return query(t[pl].ls, t[pr].ls, l, mid, k);
	else return query(t[pl].rs, t[pr].rs, mid + 1, r, k - lcnt);
}

int main()
{
    
    
	scanf("%d%d", &n, &m);
	rep(i, 1, n) 
		scanf("%d", &a[i]), b[i] = a[i];
	sort(b + 1, b + n + 1);
	q = unique(b + 1, b + n + 1) - b - 1;
	build(rt[0], 1, q);
	rep(i, 1, n)
	{
    
    
		dt = lower_bound(b + 1, b + q + 1, a[i]) - b;
		rt[i] = addt(rt[i - 1], 1, q);
	}
	rep(i, 1, m)
	{
    
    
		int lt, rtm, kt;
		scanf("%d%d%d", &lt, &rtm, &kt);
		int ans = query(rt[lt - 1], rt[rtm], 1, q, kt);
		printf("%d\n", b[ans]);
	}
	return 0;
}

E m m m . . . Emmm...E m m m . . . What's more interesting is that this problem can also useline segment tree nesting balanced tree, because the balanced tree has the function of adding and deleting, so this methodsupports dynamic modification. Specifically...not written

Regarding the division of the value range, P4587 [FJOI2016] Mysterious Numbers (solutions) is a highly comprehensive example.


I have to run away quickly. If I do the chairman tree again, my balance tree will be rotten in the ground. Run away.

—— E n d \mathfrak{End} End——

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324135192&siteId=291194637