[USACO08FEB] Hotel G

  • 线段树维护的信息很简单,关键在于怎样通过这些信息设计查询函数回答题目的询问。对于每一个区间,如果它的左儿子的msum值大于等于x,则到左儿子里去找;如果左儿子的rsum加上右儿子的lsum大于等于x,则直接返回左儿子的右端点减去左儿子的rsum值;否则到右儿子里去找
#include <bits/stdc++.h>
using namespace std;
struct t1
{
	int l,r,lsum,rsum,msum,bj;
	#define len(x) t[x].r-t[x].l+1
}t[200005];
void build(int p,int l,int r)
{
	t[p].l=l;
	t[p].r=r;
	t[p].lsum=t[p].rsum=t[p].msum=r-l+1;
	t[p].bj=-1;
	if(l==r)
	{
		return;
	}
	int mid=(l+r)>>1;
	build(p*2,l,mid);
	build(p*2+1,mid+1,r);
}
void spread(int p)
{
	if(t[p].bj!=-1)
	{
		t[p*2].bj=t[p*2+1].bj=t[p].bj;
		if(t[p].bj==0)
		{
			t[p*2].lsum=t[p*2].rsum=t[p*2].msum=len(p*2);
			t[p*2+1].lsum=t[p*2+1].rsum=t[p*2+1].msum=len(p*2+1);
		}
		else 
		{
			t[p*2].lsum=t[p*2].rsum=t[p*2].msum=0;
			t[p*2+1].lsum=t[p*2+1].rsum=t[p*2+1].msum=0;
		}
		t[p].bj=-1;
	}
}
void change(int p,int l,int r,int v)
{
	if(l<=t[p].l&&r>=t[p].r)
	{
		if(v==0)
		{
			t[p].lsum=t[p].rsum=t[p].msum=len(p);
		}
		else
		{
			t[p].lsum=t[p].rsum=t[p].msum=0;
		}
		t[p].bj=v;
		return;
	}
	spread(p);
	int mid=(t[p].l+t[p].r)>>1;
	if(l<=mid)
	{
		change(p*2,l,r,v);
	}
	if(r>mid)
	{
		change(p*2+1,l,r,v);
	}
	t[p].lsum=t[p*2].lsum;
	if(t[p*2].lsum==len(p*2))
	{
		t[p].lsum+=t[p*2+1].lsum;
	}
	t[p].rsum=t[p*2+1].rsum;
	if(t[p*2+1].rsum==len(p*2+1))
	{
		t[p].rsum+=t[p*2].rsum;
	}
	t[p].msum=max(max(t[p*2].msum,t[p*2+1].msum),t[p*2].rsum+t[p*2+1].lsum);
}
int ask(int p,int x)
{
	spread(p);
	if(t[p*2].msum>=x)
	{
		return ask(p*2,x);
	}
	else if(t[p*2].rsum+t[p*2+1].lsum>=x)
	{
		return t[p*2].r-t[p*2].rsum+1;
	}
	else
	{
		return ask(p*2+1,x);
	}
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n,m;
	cin>>n>>m;
	build(1,1,n);
	for(int i=1;i<=m;i++)
	{
		int opt,x,y;
		cin>>opt>>x;
		if(opt==1)
		{
			if(t[1].msum<x)
			{
				cout<<"0\n";
			}
			else
			{
				y=ask(1,x);
				cout<<y<<"\n";
				change(1,y,y+x-1,1);
			}
		}
		else
		{
			cin>>y;
			change(1,x,x+y-1,0);
		}
	}
	return 0;
}
posted @ 2025-02-24 20:18  D06  阅读(4)  评论(0编辑  收藏  举报
//雪花飘落效果