【线段树】[LUOGU USACO08FEB 酒店Hotel ] 区间连续最大

题目:

题目链接:[LUOGU USACO08FEB 酒店Hotel ]
题解:
这个题,就是XOR的艺术Glass Carving的结合,就是求长度为x的最小房间号的连续0,这样的话就是和Glass一样进行求线段树中的区间连续最大,再像XOR的艺术一样进行修改。

代码:

#include<bits/stdc++.h>
#define lk (k<<1)
#define rk (k<<1|1)
using namespace std;
inline int read()
{
	int s=0,w=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
	while(ch<='9'&&ch>='0')s=s*10+ch-'0',ch=getchar();
	return s*w;
}
const int sea=50100;
int n,m;
struct hit{int l,r,lm,rm,s,len,lazy;}tr[sea*4];
void build(int k,int l,int r)
{
	tr[k].l=l,tr[k].r=r;
	tr[k].lm=tr[k].rm=tr[k].s=tr[k].len=r-l+1;
	if(l==r) return; int mid=(l+r)/2;
	build(lk,l,mid); build(rk,mid+1,r);
}
void up(int k)
{
	if(tr[lk].s==tr[lk].len) tr[k].lm=tr[rk].lm+tr[lk].len;else tr[k].lm=tr[lk].lm;	
	if(tr[rk].s==tr[rk].len)
	tr[k].rm=tr[lk].rm+tr[rk].len;else tr[k].rm=tr[rk].rm;
	tr[k].s=max(max(tr[lk].s,tr[rk].s),tr[rk].lm+tr[lk].rm);
}
void down(int k)
{
	int l=tr[k].l,r=tr[k].r;
	if(l==r) return ;
	if(tr[k].lazy==1)
	{
		tr[lk].lm=tr[lk].rm=tr[lk].s=tr[lk].len;
		tr[rk].lm=tr[rk].rm=tr[rk].s=tr[rk].len;
		tr[lk].lazy=tr[rk].lazy=1;
	}
	else if(tr[k].lazy==2)
	{
		tr[lk].lm=tr[lk].rm=tr[lk].s=0;
		tr[rk].lm=tr[rk].rm=tr[rk].s=0;
		tr[lk].lazy=tr[rk].lazy=2;
	}
	tr[k].lazy=0;
}
void alter(int k,int x,int y,int ff)
{
	down(k);
	int l=tr[k].l,r=tr[k].r;
	if(l==x&&r==y)
	{
		if(ff==1) tr[k].lm=tr[k].rm=tr[k].s=tr[k].len;
		else tr[k].lm=tr[k].rm=tr[k].s=0;
		tr[k].lazy=ff;	return ;
	}
	int mid=(l+r)/2;
	if(mid>=y) alter(lk,x,y,ff);
	else if(mid<x) alter(rk,x,y,ff);
	else alter(lk,x,mid,ff),alter(rk,mid+1,y,ff);
	up(k);
}
int ask(int k,int x)
{
	down(k);
	int l=tr[k].l,r=tr[k].r,mid=(l+r)/2;
	if(l==r) return l; 
	if(tr[lk].s>=x) return ask(lk,x);
	if(tr[lk].rm+tr[rk].lm>=x) return mid-tr[lk].rm+1;
	return ask(rk,x);
}
int main()
{
	n=read(); m=read();
	build(1,1,n);
	for(int i=1;i<=m;i++)
	{
		int f,x,y;
		f=read();
		if(f==1)
		{
			x=read(); if(tr[1].s<x) puts("0");
			else{int p=ask(1,x); printf("%d\n",p);alter(1,p,p+x-1,2);}
		}
		else x=read(),y=read(),alter(1,x,y+x-1,1);
	}
	return 0;
}

Continue……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值