bzoj1593(线段树)

线段树一种新见的询问方式。

1.询问连续长度为x的空的区间的最左端点,并将这段覆盖

(通过最长子序列来做,先判断左边有没有这样的区间,再判断相连接的地方有没有,再判断右边有没有)

2.区间覆盖为空或有 

 

#include
#include
#include
#include
#include
using namespace std;

int n,ans;
struct aa
{
	int l,r,mx,qz,hz,bj;
}a[50005*4];

void up(int i)
{
	int l=i<<1,r=i<<1|1;
	a[i].mx=max(a[l].mx,a[r].mx);
	a[i].mx=max(a[i].mx,a[l].hz+a[r].qz);
	if (a[l].qz==a[l].r-a[l].l+1) a[i].qz=a[l].qz+a[r].qz;else a[i].qz=a[l].qz;
	if (a[r].hz==a[r].r-a[r].l+1) a[i].hz=a[r].hz+a[l].hz;else a[i].hz=a[r].hz;
}

void down(int i)
{
	if (a[i].bj>=0)
	{
		int k=a[i].bj;a[i].bj=-1;
		a[i<<1].bj=a[i<<1|1].bj=k;
		
		if (a[i<<1].l)
		a[i<<1].mx=a[i<<1].qz=a[i<<1].hz=k?0:a[i<<1].r-a[i<<1].l+1;
		
		if (a[i<<1|1].l)
		a[i<<1|1].mx=a[i<<1|1].qz=a[i<<1|1].hz=k?0:a[i<<1|1].r-a[i<<1|1].l+1;
	}
}
void build(int i,int l,int r)
{
	a[i].l=l;a[i].r=r;
	a[i].bj=-1;
	if (l==r)
	{
		a[i].qz=a[i].hz=a[i].mx=1;
		return ;
	}
	int mid=(l+r)>>1;
	build(i<<1,l,mid);
	build(i<<1|1,mid+1,r);
	up(i);
}
void updata(int i,int l,int r,int k)
{
	if (a[i].l==l&&a[i].r==r) 
	{
		a[i].bj=k;
		a[i].mx=a[i].qz=a[i].hz= k ? 0:a[i].r-a[i].l+1;
		return ;
	}
	down(i);
	int mid=(a[i].l+a[i].r)>>1;
	if (r<=mid) updata(i<<1,l,r,k);
	else if (l>mid) updata(i<<1|1,l,r,k);
	else updata(i<<1,l,mid,k),updata(i<<1|1,mid+1,r,k);
	up(i);
}
int fin(int i,int d)
{
	down(i);
	if (a[i].r-a[i].l+1==d&&a[i].mx==d) return a[i].l;
	if (a[i<<1].mx>=d) return fin(i<<1,d);
	if (a[i<<1].hz+a[i<<1|1].qz>=d) return a[i<<1].r-a[i<<1].hz+1;
	if (a[i<<1|1].mx>=d) return fin(i<<1|1,d);
	return 0;
}
int main()
{
	int m,op,x,d;
	scanf("%d%d",&n,&m);
	build(1,1,n);
	while (m--)
	{
		scanf("%d",&op);
		if (op==1) 
		{
			scanf("%d",&d);
			ans=fin(1,d);
			printf("%d\n",ans);
			if(ans) updata(1,ans,ans+d-1,1);
		}
		else 
		{
			scanf("%d%d",&x,&d);
			updata(1,x,x+d-1,0);
		}
	}
	return 0;
}


总结:

1:虽然变了形式,但是还是可以在线段树的优化的类型之内的,其实只要是用线段树可以优化到log (n)级别的,一般都可以考虑线段树,实际上这也不是一个很固定的东西,完全可以在理性的基础上发挥自己的创造力,尽量将线段树真正做到灵活。将线段树灵活变通,以便在其他的问题当中作为一种数据结构的优化,会大大提高效率。

你可能感兴趣的:(线段树)