AcWing 2425. 奇怪的计算器

分块做法

Solution

显然答案关于 X 是单调的,将所有询问按 X 排序。
那么每次操作需要找出一个分界点 bound , 把询问序列分为溢出和不溢出的两段。

  • 对于不溢出的段,正常维护 tag : +-*
  • 对于溢出的段,区间染色。

实现的具体 tag 是另 $$ get(i)=b[x] \times mtag[F[x]]+atag[F[x]]+ktag[F[x]] \times a[x] $$
其中 \(b[i]\) 是维护的序列, \(a[i]\) 是原序列, \(get(i)\) 为当前的真实值。

Code

#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<vector>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>

using namespace std;
typedef long long LL;
typedef unsigned long long ULL;

const int N=1e5+5,SQ=1000;

int n,m;
LL Lb,Rb;

struct Require
{
	int opt;
	LL x;
}a[N];

struct Query
{
	int id;
	LL x;
	bool operator<(const Query &t) const
	{
		return x<t.x;
	}
}q[N];

struct Block 
{
	int L[SQ],R[SQ];
	int F[N];
	
	LL mtag[SQ],atag[SQ],ktag[SQ]; // get(x) = x*mtag[] + atag[] + ktag[]*a[] 
	int siz,k;
	LL a[N],b[N];
	
	void Build()
	{
		siz=sqrt(n);
		k=n/siz+(n%siz>0);
		int i,j;
		for(i=1;i<=k;i++) {
			L[i]=R[i-1]+1;
			R[i]=i*siz;
		}
		R[k]=n;
		for(i=1;i<=k;i++) 
			for(j=L[i];j<=R[i];j++)
				F[j]=i;
		
		for(i=1;i<=n;i++) a[i]=q[i].x;
		memcpy(b,a,sizeof b);
		for(i=1;i<=k;i++) mtag[i]=1,atag[i]=ktag[i]=0;
	}
	
	void pushdown(int x)
	{
		if(mtag[x]==1&&atag[x]==0&&ktag[x]==0) return;
		for(int i=L[x];i<=R[x];i++) 
			b[i]=b[i]*mtag[x]+atag[x]+ktag[x]*a[i];
		mtag[x]=1,atag[x]=ktag[x]=0;
	}
	
	inline LL get(int x) { return b[x]*mtag[F[x]]+atag[F[x]]+ktag[F[x]]*a[x]; }
	
	void Paint(int x,int y,LL key)
	{
		if(y<x) return;
		int i;
		if(F[x]==F[y]) {
			pushdown(F[x]);
			for(i=x;i<=y;i++) b[i]=key;
			return;	
		}
		pushdown(F[x]);
		for(i=x;i<=R[F[x]];i++) b[i]=key;
		for(i=F[x]+1;i<=F[y]-1;i++) mtag[i]=0,atag[i]=key,ktag[i]=0;
		pushdown(F[y]);
		for(i=L[F[y]];i<=y;i++) b[i]=key;
	}
	
	void Add(LL key)
	{
		int i;
		for(i=1;i<=k;i++) {
			if(get(R[i])+key<=Rb) atag[i]+=key;
			else break;
		}
		if(i>k) return;
		pushdown(i);
		for(i=L[i];b[i]+key<=Rb;i++) b[i]+=key;
		Paint(i,n,Rb);
	}
	
	void Sub(LL key)
	{
		int i;
		for(i=1;i<=k && get(R[i])-key<=Lb;i++);//  printf("Query %lld\n",get(R[i]));
		if(i==k+1) {
			Paint(1,n,Lb);
			return;	
		}
		pushdown(i);
		for(i=L[i];b[i]-key<=Lb;i++);
		Paint(1,i-1,Lb);
		int x=F[i];
		for(;i<=R[x];i++) b[i]-=key;
		for(i=F[i];i<=k;i++) atag[i]-=key;
	}
	
	void Mul(LL key) 
	{
		int i;
		for(i=1;i<=k;i++) {
			if(get(R[i])*key<=Rb) 
				mtag[i]*=key,atag[i]*=key,ktag[i]*=key;
			else break;
		}
		if(i>k) return;
		pushdown(i);
		for(i=L[i];b[i]*key<=Rb;i++) b[i]*=key;
		Paint(i,n,Rb);
	}
	
	void Modify(int key)
	{
		int i;
		for(i=1;i<=k;i++) {
			if(get(R[i])+a[R[i]]*key<=Rb) ktag[i]+=key;
			else break;
		}	
		if(i>k) return;
		pushdown(i);
		for(i=L[i];b[i]+a[i]*key<=Rb;i++) b[i]+=a[i]*key;
		Paint(i,n,Rb);
	}
	
	void Recover() { for(int i=1;i<=k;i++) pushdown(i); }
	void print() 
	{
		Recover();
		for(int i=1;i<=n;i++) printf("%lld ",b[i]);
		printf("\n");
	}
}B;

LL ans[N];

int main()
{
//	freopen("1.in","r",stdin);
	
	int i;
	char opt[2];
	scanf("%d%lld%lld",&m,&Lb,&Rb);
	for(i=1;i<=m;i++) {
		scanf("%s%lld",opt,&a[i].x);
		if(*opt=='+') a[i].opt=1;
		else if(*opt=='-') a[i].opt=2;
		else if(*opt=='*') a[i].opt=3;
		else a[i].opt=4;
	}	
	
	scanf("%d",&n);
	for(i=1;i<=n;i++) {
		scanf("%lld",&q[i].x);
		q[i].id=i;
	}
	sort(q+1,q+n+1);
	B.Build();
	for(i=1;i<=m;i++) {
		if(a[i].opt==1) B.Add(a[i].x);
		else if(a[i].opt==2) B.Sub(a[i].x);
		else if(a[i].opt==3) B.Mul(a[i].x);
		else B.Modify(a[i].x);
		
//		B.print();
	}
	B.Recover();
	for(i=1;i<=n;i++) 
		ans[q[i].id]=B.b[i];
	for(i=1;i<=n;i++) printf("%lld\n",ans[i]);
	return 0;
}
posted @ 2020-11-28 21:24  cjlworld  阅读(121)  评论(0编辑  收藏  举报