ZSOI2013 花瓶 线段树

题意:给出两种操作,一种是从A开始向后放花,一种是把a到b的花全部扔掉。放过的位置就不能再次放

显然线段树,加上两种标记,一种是这块是满的,一种是这块是空的,然后第一种操作答案带上三个值

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#define LL long long
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define dfo(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
inline LL read()
{
	LL d=0,f=1;char s=getchar();
	while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
	while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
	return d*f;
}
#define N 100005
#define inf 2000000000
struct ansss
{
	int first,last,ans;
}ans;
int ls[N*3],rs[N*3],z0[N*3],w0[N*3],sum[N*3],la[N*3];
int n,m;

ansss pushans(ansss a,ansss b)
{
	ansss ret;
	ret.first=min(a.first,b.first);
	ret.last=max(a.last,b.last);
	ret.ans=a.ans+b.ans;
	return ret;
}

void pushup(int k)
{
	sum[k]=sum[k<<1]+sum[k<<1|1];
	z0[k]=min(z0[k<<1],z0[k<<1|1]);
	w0[k]=max(w0[k<<1],w0[k<<1|1]);
	if(z0[k]==inf)la[k]=1;
}

void man(int k)
{
	sum[k]=rs[k]-ls[k]+1;
	z0[k]=inf;w0[k]=-1;
}

void clear(int k)
{
	sum[k]=0;
	z0[k]=ls[k];w0[k]=rs[k];
}

ansss checkans(ansss k)
{
	if(k.ans==0)
	{
		k.first=inf;
		k.last=-1;
	}
	return k;
}

void build(int k,int l,int r)
{
	if(l==r)
	{
		ls[k]=rs[k]=l;
		clear(k);
		la[k]=0;
		return;
	}
	int mid=(l+r)>>1;
	build(k<<1,l,mid);build(k<<1|1,mid+1,r);
	ls[k]=ls[k<<1];rs[k]=rs[k<<1|1];
	pushup(k);
}

void pushlazy(int k)
{
	if(la[k]==0)return;
	if(la[k]==1)
	{
		man(k<<1);man(k<<1|1);
		la[k<<1]=la[k<<1|1]=1;
		la[k]=0;
		return ;
	}
	if(la[k]==2)
	{
		clear(k<<1);clear(k<<1|1);
		la[k<<1]=la[k<<1|1]=2;
		la[k]=0;
		return;
	}
}

ansss F(int k,int l,int r,int f)
{
	ansss ret;
	if(ls[k]==l&&rs[k]==r)
	{
		int tt=r-l+1;
		if(tt-sum[k]==0||f==0)
		{
		
			ret.first=inf;ret.last=-1;
			ret.ans=0;
			return checkans(ret);
		}
		if(f>=tt-sum[k])
		{
			ret.first=z0[k];ret.last=w0[k];
			ret.ans=tt-sum[k];
			z0[k]=inf;w0[k]=-1;
			sum[k]=tt;
			la[k]=1;
			return checkans(ret);
		}
		pushlazy(k);
		int mid=(l+r)>>1;
		ansss t=F(k<<1,l,mid,f);
		ret=F(k<<1|1,mid+1,r,f-t.ans);
		ret=pushans(t,ret);
		pushup(k);	
		return checkans(ret);
	}
	pushlazy(k);
	int mid=(ls[k]+rs[k])>>1;
	if(l>mid)ret=F(k<<1|1,l,r,f);else
	{
		if(r<=mid)ret=F(k<<1,l,r,f);else
		{
			ansss t=F(k<<1,l,mid,f);
			ret=F(k<<1|1,mid+1,r,f-t.ans);
			ret=pushans(t,ret);
		}
	}
	pushup(k);
	return checkans(ret);
}
	
int R(int k,int l,int r)
{
	int ret=0;
	if(ls[k]==l&&rs[k]==r)
	{
		ret=sum[k];
		clear(k);
		la[k]=2;
		return ret;
	}
	pushlazy(k);
	int mid=(ls[k]+rs[k])>>1;
	if(r<=mid)ret=R(k<<1,l,r);else
	{
		if(l>mid)ret=R(k<<1|1,l,r);else
		{
			ret=R(k<<1,l,mid)+R(k<<1|1,mid+1,r);
		}
	}
	pushup(k);
	return ret;
}

int main()
{
	freopen("vase.in","r",stdin);
	freopen("vase.out","w",stdout);
	n=read(),m=read();
	build(1,0,n-1);
	fo(i,1,m)
	{
		int ch=read(),x=read(),y=read();
		if(ch==1)
		{
			ans=F(1,x,n-1,y);
			if(ans.ans<=0)puts("Can not put any one.");
			else printf("%d %d\n",ans.first,ans.last);
		}else printf("%d\n",R(1,x,y));
	}
	return 0;
}


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