Weight line segment tree
The so-called weighted line segment tree is a maintenance value rather than a subscript line segment tree. I personally prefer to call it a range line segment tree.
Chestnut: For a given array, a normal segment tree can maintain the sum of the numbers in a subarray, while a weighted segment tree can maintain the number of occurrences of array elements in an interval.
In implementation, because the range of values is usually large, the weighted line segment tree will use discretization or dynamic opening strategy to optimize the space.
Update operation:
When updating, we insert a value v into the line segment tree, so all interval values containing v need to be + 1. (How many numbers appear in the corresponding interval of each node maintenance)
int update (long long v,long long l,long long r,int pos) { // Insert v, the current interval is [l,r]. if (!pos) pos=++tot_node; // If the node does not exist, a new node is created. if (l<=v&&v<=r) { // If the current interval contains an insert value. tree[pos].val++; // Number of occurrences + 1. if (l==r) return pos; // If it recurs to the leaf node, exit. } long long mid=(l+r)>>1; if (v<=mid) tree[pos].ls=update(v,l,mid,tree[pos].ls); else tree[pos].rs=update(v,mid+1,r,tree[pos].rs); // Determine which half of the current interval the insertion value is. pushup(pos); // To flash back. return pos; }
Query operation:
Query operations are similar to binary trees.
long long query (long long l,long long r,long long L,long long R,int pos) { // The number of numbers in the query interval [L, R], the current interval is [l, r]. if (!pos) return 0; // If the node does not exist, it must not have arrived. if (L<=l&&r<=R) { // If the current interval belongs to the query interval. return tree[pos].val; // Returns the number of numbers in the interval directly. } long long mid=(l+r)>>1,ans=0; if (L<=mid) ans+=query(l,mid,L,R,tree[pos].ls); if (mid<R) ans+=query(mid+1,r,L,R,tree[pos].rs); // Statistical interval sum. return ans; }
Exercise questions:
As an exercise template, you can consider reverse pairs. The general idea is the number of elements per query a[i]+1~n.
Segment Tree Merging
The so-called line segment tree merging is to obtain information by merging two line segment trees. Its correctness is guaranteed by the stable structure of the line segment tree.
Line segment tree merging is usually a bottom-up process, which merges the tree of the child node into the parent node on the way of deep search, thus realizing the statistics of the value of the parent node.
The complexity of line segment tree merging is (n logn), one less than heuristic merging.
It is not difficult to find that if the original idea of line segment tree merging is directly established at each node that needs to be traversed, a line segment tree will surely explode. Here you can use a method called "memory recovery": since the information of the child node has been put into the parent node after merging, so the child node is useless, then all its nodes can be reclaimed and thrown into a memory pool. When updating later, the node can be retrieved from the memory pool instead of creating a new node.
Recycle memory:
inline int newId () { if (pool_top) return mempool[pool_top--]; return ++tot_node; } inline void killId (int &x) { mempool[++pool_top]=x; tree[x].ls=tree[x].rs=tree[x].val=0; x=0; }
Merge operation:
The merge operation is similar to the merge of left-handed trees in that each node is merged recursively.
int merge (int l,int r,int x,int y) { if (!x||!y) return x+y; int now=newId(),mid=(l+r)>>1; if (l==r) { tree[now].val=tree[x].val+tree[y].val; } else { tree[now].ls=merge(l,mid,tree[x].ls,tree[y].ls); tree[now].rs=merge(mid+1,r,tree[x].rs,tree[y].rs); tree[now].val=tree[tree[now].ls].val+tree[tree[now].rs].val; } killId(x),killId(y); return now; }
Exercise questions:
Consider doing Tree Rotation. The general idea is to give a binary tree, which can exchange left and right subtrees of each point, requiring that the preface traverse the leaves in reverse order at least.
Since the exchange of left and right sons does not affect the upper values, it can be counted directly at each merger.