POJ 3667 线段树 区间合并经典题目

区间染色  二分逼近查找

区间合并部分很简单  query方式稍有不同 分别对每种情况处理即可


#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "math.h"


struct comp
{
	int l,r,mid,lazy;
	int lsum,rsum,sum;
} data[300001];
int key;

int max(int a,int b)
{
	if (a<b) return b;
	else return a;
}

void build(int l,int r,int k)
{
	data[k].l=l;
	data[k].r=r;
	data[k].mid=(l+r)/2;
	data[k].lazy=-1;
	data[k].lsum=data[k].rsum=data[k].sum=data[k].r-data[k].l+1;

	if (l==r) return ;

	build(l,data[k].mid,k*2);
	build(data[k].mid+1,r,k*2+1);
}



void Pushdown(int k)
{
	int ll,rr;
	if (data[k].l==data[k].r) return ;

	if (data[k].lazy!=-1)
	{
		data[k*2].lazy=data[k*2+1].lazy=data[k].lazy;

		ll=data[k*2].r-data[k*2].l+1;
		rr=data[k*2+1].r-data[k*2+1].l+1;

		if (data[k].lazy==1)
		{
			data[k*2].lsum=data[k*2].rsum=data[k*2].sum=ll;
			data[k*2+1].lsum=data[k*2+1].rsum=data[k*2+1].sum=rr;
		}
		else 
		{
			data[k*2].lsum=data[k*2].rsum=data[k*2].sum=0;
			data[k*2+1].lsum=data[k*2+1].rsum=data[k*2+1].sum=0;
		}

		data[k].lazy=-1;
		return ;

	}

}
			

void Pushup(int k)
{
	int ll,rr;
	ll=data[k*2].r-data[k*2].l+1;
	rr=data[k*2+1].r-data[k*2+1].l+1;

	data[k].lsum=data[k*2].lsum;
	if (data[k].lsum==ll) data[k].lsum+=data[k*2+1].lsum;

	data[k].rsum=data[k*2+1].rsum;
	if (data[k].rsum==rr) data[k].rsum+=data[k*2].rsum;

	data[k].sum=max(max(data[k*2].sum,data[k*2+1].sum),data[k*2].rsum+data[k*2+1].lsum);
}

int  query(int n,int k)
{
	Pushdown(k);
	if (data[k*2].lsum>=n) return data[k*2].l; // 在左子树最左直接输出位置
	else 
		if (data[k*2].sum>=n) return query(n,k*2); // 在左子树中查询
		else
			if (data[k*2].rsum+data[k*2+1].lsum>=n) return  data[k*2].r-data[k*2].rsum+1; // 在中间直接输出位置
			else 
				if (data[k*2+1].sum>=n) return query(n,k*2+1); // 在右子树中查询
				else return 0; 
}


void insert(int l,int r,int k)
{
	if (data[k].l==l && data[k].r==r)
	{
		data[k].lsum=data[k].rsum=data[k].sum=0;
		data[k].lazy=0;
		return ;
	}

	Pushdown(k);

	if (r<=data[k].mid) insert(l,r,k*2);
	else 
		if (l>data[k].mid) insert(l,r,k*2+1);
		else 
		{
			insert(l,data[k].mid,k*2);
			insert(data[k].mid+1,r,k*2+1);
		}

	Pushup(k);
}

void update(int l,int r,int k)
{
	if (data[k].l==l && data[k].r==r)
	{
		data[k].lsum=data[k].rsum=data[k].sum=data[k].r-data[k].l+1;
		data[k].lazy=1;
		return ;
	}

	Pushdown(k);

	if (r<=data[k].mid) update(l,r,k*2);
	else 
		if (l>data[k].mid) update(l,r,k*2+1);
		else 
		{
			update(l,data[k].mid,k*2);
			update(data[k].mid+1,r,k*2+1);
		}

	Pushup(k);
}





int main()
{
	int n,m,op,x,y;
	while (scanf("%d%d",&n,&m)!=EOF)
	{
		build(1,n,1);
		while (m--)
		{
			scanf("%d",&op);
			if (op==1)
			{
				scanf("%d",&x);
				key=query(x,1);
				printf("%d\n",key);
				if (key!=0) insert(key,key+x-1,1);
			}
			else 
			{
				scanf("%d%d",&x,&y);
				update(x,x+y-1,1);
			}
		}
	}
	return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值