题解 CF121E Lucky Array

这是一道线段树的好题。

这个题的翻译有一点没翻译出来,就是无论怎么加序列中的数不会超过(10^4)

那么在这个数据范围内可以发现由(4)(7)组成的数只有(30)

所以我们可以打一个小小的表。

为了防抄袭我的表打的是(2,3)组成的数。

可以看到我的表最后插入了一个极大值,这个原因请自行思考,不再赘述。

有了这个表之后我们可以维护每个数与最小的比它大的由(4)(7)组成的数的差,每次区间加用线段树维护,把差值减去(d)

线段树维护一下这个区间的最小值以及最小值出现的次数,每次询问我们看如果最小值是(0)的话就直接返回最小值出现的次数即可,因为它一定是由(4)(7)组成的。

当差值减小到比(0)还小的时候,我们就要对(x)维护下一个小于(x)且里(x)最近的(4,7) 组成的数的差值。这个维护的时候暴力维护,重新建树,每个数最多被修改(31)次,所以不会超时。

复杂度(O(31mlog n))

代码

#include<bits/stdc++.h>
#define eps 1e-7
#define re register
#define N 2001001
#define MAX 2011
#define PI 3.1415927
#define inf 1e18
using namespace std;
typedef long long ll;
typedef double db;
const ll mod=1000000007;
inline void read(re ll &ret)
{
    ret=0;re ll pd=0;re char c=getchar();
    while(!isdigit(c)){pd|=c=='-';c=getchar();}
    while(isdigit(c)){ret=(ret<<1)+(ret<<3)+(c^48);c=getchar();}
    ret=pd?-ret:ret;
}
ll n,m,a[N],b[N],x,y,tmp;
struct node
{
	ll l,r,mid,val,minn,sum;
}seg[N];
ll num[32]={0,2,3,22,23,32,33,222,223,232,233,322,323,332,333,2222,2223,2232,2233,2322,2323,2332,2333,3222,3223,3232,3233,3322,3323,3332,3333,200001}; 
char s[N];
inline void pushup(re ll pos)
{
	seg[pos].minn=min(seg[pos<<1].minn,seg[pos<<1|1].minn);
	if(seg[pos].minn==seg[pos<<1].minn&&seg[pos].minn==seg[pos<<1|1].minn)
		seg[pos].val=seg[pos<<1].val+seg[pos<<1|1].val;
	else if(seg[pos].minn==seg[pos<<1].minn)
		seg[pos].val=seg[pos<<1].val;
	else
		seg[pos].val=seg[pos<<1|1].val;
	return;
}
inline void build(re ll pos,re ll l,re ll r)
{
	seg[pos].l=l;
	seg[pos].r=r;
	seg[pos].mid=l+r>>1;
	if(l==r)
	{
		seg[pos].val=1;
		for(re int i=1;i<=31;i++)
		{
			seg[pos].minn=num[i]-a[l];
			b[l]=i;
			if(num[i]>=a[l])
				break;
		}
	}
	else
	{
		build(pos<<1,l,seg[pos].mid);
		build(pos<<1|1,seg[pos].mid+1,r);
		pushup(pos);
	}
	return;
}
inline void rebuild(re ll pos)
{
	if(seg[pos].minn>=0)
		return;
	if(seg[pos].l==seg[pos].r)
	{
		a[seg[pos].l]=num[b[seg[pos].l]]-seg[pos].minn;
		for(re int i=1;i<=31;i++)
		{
			seg[pos].minn=num[i]-a[seg[pos].l];
			b[seg[pos].l]=i;
			if(num[i]>=a[seg[pos].l])
				break;
		}
	}
	else
	{
		seg[pos<<1].minn-=seg[pos].sum;
		seg[pos<<1].sum+=seg[pos].sum;
		seg[pos<<1|1].minn-=seg[pos].sum;
		seg[pos<<1|1].sum+=seg[pos].sum;
		seg[pos].sum=0;
		rebuild(pos<<1);
		rebuild(pos<<1|1);
		pushup(pos);
	}
}
inline void add(re ll pos,re ll num)
{
	seg[pos].sum+=num;
	seg[pos].minn-=num;
	if(seg[pos].minn<0)
		rebuild(pos);
	return;
}
inline void pushdown(re ll pos)
{
	add(pos<<1,seg[pos].sum);
	add(pos<<1|1,seg[pos].sum);
	seg[pos].sum=0;
	return;
}
inline void upgrade(re ll pos,re ll l,re ll r,re ll num)
{
	if(seg[pos].l>r||seg[pos].r<l)
		return;
	else if(seg[pos].l>=l&&seg[pos].r<=r)
		return add(pos,num);
	pushdown(pos);
	upgrade(pos<<1,l,r,num);
	upgrade(pos<<1|1,l,r,num);
	pushup(pos);
	return;
}
inline pair<ll,ll> query(re ll pos,re ll l,re ll r)
{
	if(seg[pos].l>=l&&seg[pos].r<=r)
		return make_pair(seg[pos].val,seg[pos].minn);
	else if(seg[pos].l>r||seg[pos].r<l)
		return make_pair(0,inf);
	pushdown(pos);
	re pair<ll,ll> x=query(pos<<1,l,r),y=query(pos<<1|1,l,r);
	re ll ans=0;
	if(x.second==y.second)
		ans+=x.first+y.first;
	else if(x.second>y.second)
		ans+=y.first;
	else if(x.second<y.second)
		ans+=x.first;
	return make_pair(ans,min(x.second,y.second));
}
int main()
{
	read(n);
	read(m);
	for(re int i=1;i<=n;i++)
		read(a[i]);
	build(1,1,n);
	for(re int i=1;i<=m;i++)
	{
		scanf("%s",s+1);
		if(s[1]=='c')
		{
			read(x);
			read(y);
			re pair<ll,ll>temp=query(1,x,y);
			if(!temp.second)
				printf("%lld
",temp.first);
			else
				puts("0"); 
		}
		else if(s[1]=='a')
		{
			read(x);
			read(y);
			read(tmp);
			upgrade(1,x,y,tmp);
		}
	}
	exit(0);
}

原文地址:https://www.cnblogs.com/CelticBlog/p/13531817.html