Segment tree interval merge operation (POJ3667)

Interval merge operation of line segment tree

  • When the interval of the line segment tree merges operation and maintenance information, in addition to interval sum, update flags, etc., the most important thing is to maintain the two special values ​​of lsum and rsum
  • The meanings of these two values ​​respectively are: lsum represents the length of the continuous segment starting from the left end of the interval (left continuous segment), rsum represents the length of the continuous segment starting from the right end of the interval (note the end) ( Right continuous segment), and rsum[rt<<|1]+lsum[rt<<1|1] represents the maximum continuous segment length including the end point of the current interval.
  • Another value that needs to be maintained is sum[rt], which is the length of the maximum continuous interval under the current node. For each lsum and rsum update, sum[rt] should be given as follows:
  • sum[rt] = max(rsum[rt<<1]+lsum[rt<<1|1],max(sum[rt<<1],sum[rt<<1|1])
  • Its value is in the maximum continuous interval of the left subtree, and the maximum continuous interval of the right subtree and the middle continuous segment take the maximum value
  • In addition, the interval merging is mainly reflected in the change of the pushup function in the operation of the line segment tree:
void pushup(int rt,int tot)
{
    
    
	if(tot == 1) return ;
	lsum[rt] = lsum[rt<<1];
	rsum[rt] = rsum[rt<<1|1];
	// 体现区间合并的地方
	if(lsum[rt] == (tot-tot/2)) lsum[rt]+=lsum[rt<<1|1];//代表左子树的区间满了需要加上右子树左区间
	if(rsum[rt] == (tot/2)) rsum[rt]+=rsum[rt<<1];// 和上方同理
	sum[rt] = max(rsum[rt<<1]+lsum[rt<<1|1],max(sum[rt<<1],sum[rt<<1|1]));
}

POJ3667 HDU4553 (it’s a bit more troublesome to maintain two trees than the previous one).
Both of these questions require the return of a query location information, which is written in the query function.

int query(int rt,int l,int r,int len)// len代表需要满足的区间长度
{
    
    
	if(l == r) return l;
	pushdown(rt,r-l+1);
	int mid = (l+r)>>1;
	if(sum[rt<<1] >= len) return query(rt<<1,l,mid,len);//做子树区间满足要求 那么位置一定在左子树区间中
	else if(rsum[rt<<1]+lsum[rt<<1|1] >= len) return mid-rsum[rt<<1]+1;// 中间段满足要求 那么起始点一点是左子树右连续区间的起点
	else return query(rt<<1|1,mid+1,r,len);//其他情况就一定存在于右子树中
}

Code:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 5e4+7;
int sum[MAXN<<2],lsum[MAXN<<2],rsum[MAXN<<2];
int lazy[MAXN<<2];
// 这个就是 hdu4553的弱化版
// 这中区间一个起始位置的题目应该都是一个套路
// 区间合并的关键 在pushup中 而query或者其他函数需要根据具体题目具体 确定
void pushup(int rt,int tot)
{
    
    
	if(tot == 1) return ;
	lsum[rt] = lsum[rt<<1];
	rsum[rt] = rsum[rt<<1|1];
	if(lsum[rt] == (tot-tot/2)) lsum[rt]+=lsum[rt<<1|1];
	if(rsum[rt] == (tot/2)) rsum[rt]+=rsum[rt<<1];
	sum[rt] = max(rsum[rt<<1]+lsum[rt<<1|1],max(sum[rt<<1],sum[rt<<1|1]));
}

void pushdown(int rt,int tot)
{
    
    
	if(tot == 1) return ;
	if(lazy[rt]){
    
    
		lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt];
		if(lazy[rt] == 2){
    
    
			sum[rt<<1] = lsum[rt<<1] = rsum[rt<<1] = tot-tot/2;
			sum[rt<<1|1] = lsum[rt<<1|1] = rsum[rt<<1|1] = tot/2;
		}
		else if(lazy[rt] == 1){
    
    
			sum[rt<<1] = lsum[rt<<1] = rsum[rt<<1] = 0;
			sum[rt<<1|1] = lsum[rt<<1|1] = rsum[rt<<1|1] = 0;
		}
		lazy[rt] = 0;
	}
}

void build(int rt,int l,int r)
{
    
    
	lazy[rt] = 0;
	if(l == r){
    
    
		sum[rt] = lsum[rt] = rsum[rt] = 1;
		return ;
	}
	//pushdown(rt,r-l+1);
	int mid = (l+r)>>1;
	build(rt<<1,l,mid);
	build(rt<<1|1,mid+1,r);
	pushup(rt,r-l+1);
}

void update(int rt,int l,int r,int ul,int ur,int p)
{
    
    
	if(l>=ul&&r<=ur){
    
    
		if(p == 1){
    
    
			sum[rt] = lsum[rt] = rsum[rt] = 0;
		}
		else if(p == 2){
    
    
			sum[rt] = lsum[rt] = rsum[rt] = r-l+1;
		}
		lazy[rt] = p;
		return ;
	}
	pushdown(rt,r-l+1);
	int mid = (l+r)>>1;
	if(ul <= mid) update(rt<<1,l,mid,ul,ur,p);
	if(ur > mid) update(rt<<1|1,mid+1,r,ul,ur,p);
	pushup(rt,r-l+1);
}

int query(int rt,int l,int r,int len)
{
    
    
	if(l == r) return l;
	pushdown(rt,r-l+1);
	int mid = (l+r)>>1;
	if(sum[rt<<1] >= len) return query(rt<<1,l,mid,len);
	else if(rsum[rt<<1]+lsum[rt<<1|1] >= len) return mid-rsum[rt<<1]+1;
	else return query(rt<<1|1,mid+1,r,len);
}

int main()
{
    
    
	int n,m;
	scanf("%d%d",&n,&m);
	build(1,1,n);
	int k;
	while(m--){
    
    
		scanf("%d",&k);
		if(k == 1){
    
    
			int len;
			scanf("%d",&len);
			if(sum[1]>=len){
    
    
				int pos = query(1,1,n,len);
				printf("%d\n",pos);
				update(1,1,n,pos,pos+len-1,1);
			}
			else printf("0\n");
		}
		else if(k == 2){
    
    
			int st,len;
			scanf("%d%d",&st,&len);
			update(1,1,n,st,st+len-1,2);
		}
	}
	return 0;
}

Guess you like

Origin blog.csdn.net/weixin_45672411/article/details/107221574