Codeforces GYM102307 J. Jail Destruction 题解

119 阅读2分钟

题目链接

思路

两种操作:区间减和区间查询。
最初考虑用线段树维护区间和以及区间最小值。对于每次区间减(al,ar,val)(al,ar,val),如果其中的一个区间最小值大于valval,那就直接对该区间减去valval,并打上懒标记,否则的话就单点修改。超时。
优化:如果一个元素pp被减为00,就可以直接把它忽略,因为pp并不影响对包含pp的区间实施区间减操作的效果。维护ct[i]ct[i],代表每个区间的非零叶子数目。如果一个元素被减为00,则将该元素的值变为INFINF,即在维护其祖先区间最小值时将该点忽略。这样就可以做到对一个区间,所有的值要么大于valval,要么为00,可以在深度较浅处直接修改并返回。

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(ll i=st;i<=ed;++i)
#define lc p<<1
#define rc p<<1|1
using namespace std;
typedef long long ll;
ll n,q;
const ll N=1E5+10,INF=0x3f3f3f3f;
ll a[N],t[N<<2],mi[N<<2],ct[N<<2],tag[N<<2];
void update(ll p)
{
	t[p]=t[lc]+t[rc];
	mi[p]=min(mi[lc],mi[rc]);
	ct[p]=ct[lc]+ct[rc];
}
void build(ll p,ll l,ll r)
{
	if(l==r)
	{
		t[p]=a[l];
		mi[p]=a[l];
		ct[p]=1;
		return;
	}
	ll mid=(l+r)>>1;
	build(lc,l,mid);
	build(rc,mid+1,r);
	update(p);
}
void flag(ll p,ll val)
{
	t[p]-=ct[p]*val;
	mi[p]-=val;
	tag[p]-=val;
}
void push_down(ll p,ll l,ll r)
{
	if(!tag[p])
		return;
	ll mid=(l+r)>>1;
	flag(lc,-tag[p]);
	flag(rc,-tag[p]);
	tag[p]=0;
}
void add(ll p,ll l,ll r,ll al,ll ar,ll val)
{
	if(!ct[p])
		return;
	if(l==r)
	{
		t[p]=max(0ll,t[p]-val);
		mi[p]=t[p];
		if(t[p]==0)
		{
			mi[p]=INF;
			ct[p]=0;
		}
		return;
	}
	if(mi[p]>=val && al<=l && ar>=r)
	{
		t[p]-=ct[p]*val;
		mi[p]-=val;
		tag[p]-=val;
		return;
	}
	push_down(p,l,r);
	ll mid=(l+r)>>1;
	if(al<=mid)
		add(lc,l,mid,al,ar,val);
	if(ar>mid)
		add(rc,mid+1,r,al,ar,val);
	update(p);
}
ll query(ll p,ll l,ll r,ll al,ll ar)
{
	ll ret=0;
	if(al<=l && ar>=r)
		return t[p];
	push_down(p,l,r);
	ll mid=(l+r)>>1;
	if(al<=mid)
		ret+=query(lc,l,mid,al,ar);
	if(ar>mid)
		ret+=query(rc,mid+1,r,al,ar);
	return ret;
}
int main()
{
	scanf("%lld%lld",&n,&q);
	rep(i,1,n)
		scanf("%lld",a+i);
	build(1,1,n);
	while(q--)
	{
		ll op,l,r;
		ll val;
		scanf("%lld",&op);
		scanf("%lld %lld",&l,&r);
		if(op==1)
		{
			if(l<=r)
				printf("%lld\n",query(1,1,n,l,r));
			else
				printf("%lld\n",query(1,1,n,l,n)+query(1,1,n,1,r));
			
		}
		else
		{
			scanf("%lld",&val);
			if(l<=r)
				add(1,1,n,l,r,val);
			else
			{
				add(1,1,n,1,r,val);
				add(1,1,n,l,n,val);
			}
		}
	}
}