Summary of various line segment trees (all take the maximum as an example)
Line segment tree, used to query some specific values of the interval (such as: maximum, minimum, average), support new creation, modification and query operations, the space should be opened 4 times, pay attention to the initialization when creating
1. New
void build(int l,int r,int x)
{
tree[x]={
l,r,0};//在这里不初始化也行,因为已经默认为0了
if(l==r)
return;
int mid=l+r>>1;
build(l,mid,x<<1);
build(mid+1,r,x<<1|1);
}
2. Modify
void modify(int x,int u,int v)
{
if(tree[x].l==u&&tree[x].r==u)//是那个点
{
tree[x].v=v;
return;
}
int mid=tree[x].l+tree[x].r>>1;
if(u<=mid)
modify(x<<1,u,v);//那个点在左边
else
modify(x<<1|1,u,v);//反之
tree[x].v=max(tree[x<<1].v,tree[x<<1|1].v);//上传
}
3. Query
int query(int x,int l,int r)
{
if(tree[x].l>=l&&tree[x].r<=r)//在区间内
return tree[x].v;
int mid=tree[x].l+tree[x].r>>1,sum=0;
if(l<=mid)
sum=query(x<<1,l,r);
if(r>mid)
sum=max(sum,query(x<<1|1,l,r));//统计左右答案
return sum;
}
Line segment tree deformation
1. Interval modification
In fact, if the modified interval is already included in the current interval, modify the entire interval and mark the following. If it is recursed, modify it
void pushdown(int x)
{
tree[x<<1].add+=tree[x].add;
tree[x<<1|1].add+=tree[x].add;//下传
tree[x<<1].sum+=(tree[x<<1].r-tree[x<<1|1].l+1)*tree[x].add;
tree[x<<1|1].sum+=(tree[x<<1|1].r-tree[x<<1|1|1].l+1)*tree[x].add;//更新值
}
void modify(int x,int l,int r,int v)
{
if(tree[x].l>=l&&tree[x].r<=r)
{
tree[x].v+=(tr[x].r-tr[x].l+1)*v;
tree[x].add+=v;//标记
return;
}
pushdown(x);//下传
int mid=tr[x].l+tr[x].r>>1;
if(l<=mid)
modify(x<<1,l,r,v);
if(r>mid)
modify(x<<1|1,l,r,v);
tree[x].v=max(tree[x<<1].v,tree[x<<1|1].v);
}
int query(int x,int l,int r)
{
if(tree[x].l>=l&&tree[x].r<=r)
return tree[x].v;
pushdown(x);//下传
int mid=tree[x].l+tree[x].r>>1,sum=0;
if(l<=mid)
sum=query(x<<1,l,r);
if(r>mid)
sum=max(sum,query(x<<1|1,l,r));
return sum;
}
2. Weight line segment tree
The weighted line segment tree counts the number of each number, which is equivalent to a "bucket". Usually solve the k-th small (big) problem. Support insert operation.
void modify(int x,int k,int cnt)
{
tree[x].v+=cnt;//每一个递归到的都结点都会加cnt
if(tree[x].l==k&&tree[x].r==k)
return;
int mid=tree[x].l+tree[x].r>>1;
if(k<=mid)
modify(x<<1,k,cnt);
else
modify(x<<1|1,k,cnt);
}
int findk(int x,int k)//这里以求k小为例
{
if(tree[x].l==tree[x].r)
return tree[x].l;
int mid=tree[x].l+tree[x].r>>1;
if(tree[x<<1].v>=k)//在左子树中
return findk(x<<1,k);
else
return findk(x<<1|1,k-tree[x<<1].v);//减去左子树的个数
}
3. Dynamic open point line segment tree
For dynamic opening, actually set the left and right to a non-fixed value. When a new point comes, apply for a new point, saving memory.
void modify(int &x,int u,int v,int l,int r)
{
if(!tree[x].num)
tree[x].num=x=++cnt;//一个新的点
if(l==u&&r==u)
{
tree[x].v=v;
return;
}
int mid=l+r>>1;
if(u<=mid)
modify(tree[x].l,u,v,l,mid);
else
modify(tree[x].r,u,v,mid+1,r);
tree[x].v=max(tree[tree[x].l].v,tree[tree[x].r].v);
}
Of course, you can also modify the interval
4. Line segment tree merge
The line segment tree is merged, and the data of two line segment trees can be summarized into one line segment tree. But the space complexity is generally high
int merge(int x,int y)
{
if(!x||!y)
return x+y;//两个相加,得到的是有数的那个数,如果都没有就是0
int u=++cnt;//开新结点
tree[u].v=tree[x].v+tree[y].v;//合并一个都有数的点
tree[u].l=merge(tree[x].l,tree[y].l);
tree[u].r=merge(tree[x].r,tree[y].r);//两个树同位置结点
return u;
}
5. Persistent line segment tree
The persistent line segment tree is a line segment tree that can save the version of the previous line segment tree.
void modefy(int x,int l,int r,int u,int v)
{
++cnt;//新点
if(l==r)
{
tr[cnt].v=v;
return cnt;
}
int mid=l+r>>1,temp=cnt;
if(u<=mid)
{
tr[cnt].rson=tr[x].rson;//没变化,直接连边
tr[cnt].lson=modefy(tr[x].lson,l,mid,u,v);//有变化,开新点
}
else
{
tr[cnt].lson=tr[x].lson;//没变化,直接连边
tr[cnt].rson=modefy(tr[x].rson,mid+1,r,u,v);//有变化,开新点
}
return temp;
}