线段树(3)之区间合并(基础题)

      提一下,博主的英语四级过了微笑,就是这么6(虽然考了两回)

      区间合并:这类题目会询问区间中满足条件的连续最长区间,所以PushUp的时候需要对左右儿子的区间进行合并,因为有可能合并之后连续最长区间比左右儿子的都长。大概就是这样。微笑上题:

总时间限制:
1000ms
内存限制:
65535kB
描述

有一个苦逼的种树人XX,需要种一排树,为什么说苦逼呢?因为总有一些熊孩子去把树苗拔掉(具体拔掉做什么,你们可以YY一下)。为了简化问题,把可以种树的位置编号为1-n。XX每次选择一个位置种树(如果已经有树了,则忽略),而熊孩子每次也选择一个位置拔树(如果没有树,则忽略)。现在XX想知道每次种树或者拔树后的连续有树的区间的最长长度。

输入
多组数据(大约10组)。对于每组数据:
第一行n,m;
接下来m行,每行q,a;
其中,q为1时表示XX种树,q为2时表示熊孩子拔树,a表示位置。
数据范围:1<=n,m<=10000,1<=q<=2,1<=a<=n。
输出
对于每组数据,输出m行,每次操作后的结果。
样例输入
4 5
1 1
1 3
1 4
2 4
1 2
样例输出
1
1
2
1
3
提示
开始状态都没有种树

这道题比较简单,因为还没涉及延迟更新,只涉及最基本的点更新,贴代码:
#include<stdio.h>
#define MAX 10000
struct node
{
	int l,r,mid;
	int lMax,rMax;  //分别是某个区间内左边界与右边界最长连续子区间长度
	int max;     //某个区间内最长连续子区间长度 
};
int Max(int a,int b)
{
	if(a>b)return a;
	else return b;
}
node t[MAX*4];
int n;
void BuildTree(int i,int l,int r)
{
	t[i].l=l;
	t[i].r=r;
	if(l==r)
	{
		t[i].max=0;
		t[i].lMax=t[i].rMax=0;
		return;
	}
	t[i].mid=(l+r)/2;
	BuildTree(i*2,l,t[i].mid);
	BuildTree(i*2+1,t[i].mid+1,r);
	t[i].max=0;
	t[i].lMax=t[i].rMax=0;
}
void PushUp(int i)    //合并区间核心代码
{
	t[i].max=Max(t[i*2].rMax+t[i*2+1].lMax,
		Max(t[i*2+1].max,t[i*2].max));
	if(t[i*2].r-t[i*2].l+1==t[i*2].max)
		t[i].lMax=t[i*2].max+t[i*2+1].lMax;
	else t[i].lMax=t[i*2].lMax;
	if(t[i*2+1].r-t[i*2+1].l+1==t[i*2+1].max)
		t[i].rMax=t[i*2+1].max+t[i*2].rMax;
	else t[i].rMax=t[i*2+1].rMax;
}
void Update(int i,int index,int num)
{
	if(t[i].l==t[i].r)
	{
		if(t[i].max==0&&num==1)
			t[i].max=t[i].rMax=t[i].lMax=1;
		else if(t[i].max==1&&num==2)
			t[i].max=t[i].rMax=t[i].lMax=0;
		return;
	}
	if(index<=t[i].mid)Update(i*2,index,num);
	else Update(i*2+1,index,num);
	PushUp(i);
}
int main()
{
	int m,i,q,a;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		BuildTree(1,1,n);
		for(i=0;i<m;i++)
		{
			scanf("%d%d",&q,&a);
			Update(1,a,q);
			printf("%d\n",t[1].max);
		}
	}
	return 0;
}
好了,睡觉了,明天还有培训。再见

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值