Operación de fusión de intervalo de árbol de segmentos (POJ3667)

Operación de fusión de intervalo del árbol de segmento de línea

  • Cuando el intervalo del árbol del segmento de línea fusiona la información de operación y mantenimiento, además de la suma del intervalo, las banderas de actualización, etc., lo más importante es mantener los dos valores especiales de lsum y rsum
  • Los significados de estos dos valores respectivamente son: lsum representa la longitud del segmento continuo comenzando desde el extremo izquierdo del intervalo (segmento continuo izquierdo), rsum representa la longitud del segmento continuo comenzando desde el extremo derecho del intervalo (observe el final) ( Segmento continuo derecho), y rsum [rt << | 1] + lsum [rt << 1 | 1] representa la longitud máxima del segmento continuo, incluido el punto final del intervalo actual.
  • Otro valor que debe mantenerse es sum [rt], que es la longitud del intervalo continuo máximo bajo el nodo actual. Para cada actualización de lsum y rsum, sum [rt] se debe dar de la siguiente manera:
  • suma [rt] = max (rsum [rt << 1] + lsum [rt << 1 | 1], max (suma [rt << 1], suma [rt << 1 | 1])
  • Su valor está en el intervalo continuo máximo del subárbol izquierdo, y el intervalo continuo máximo del subárbol derecho y el segmento continuo medio toman el valor máximo.
  • Además, la combinación de intervalos se refleja principalmente en el cambio de la función pushup en el funcionamiento del árbol de segmento de línea:
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 (es un poco más problemático mantener dos árboles que el anterior).
Ambas preguntas requieren la devolución de una información de ubicación de consulta, que se escribe en la función de consulta.

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);//其他情况就一定存在于右子树中
}

Código:

#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;
}

Supongo que te gusta

Origin blog.csdn.net/weixin_45672411/article/details/107221574
Recomendado
Clasificación