BZOJ3878 [Ahoi2014]奇怪的计算器
Description
对于一个储存数据大小只有[L,R]的计算器,有4个操作,
1、+ a:表示将当前的结果加上a;
2、- a:表示将当前的结果减去a;
3、* a:表示将当前的结果乘以a;
4、@ a:表示将当前的结果加上a*X(X是一开始输入的数)。
计算器每次会把超过R或低于L的储存为R或L继续后续计算。
给定n个操作,与q个数,求出每个数计算后的答案。
Input
输入文件的第一行包含三个正整数,N,L和R;
第接下来N行,每行一个指令,每个指令如题述,由一个字符和一个正整
数组成,字符和正整数中间有一个空格隔开;
第N+2行包含一个整数Q,表示输入的数的数量;
第接下来Q行每行一个正整数,第k个正整数Xk表示在第k次输入的
整数。
Output
输出Q行每行一个正整数,第k行的整数表示输入Xk后,依次经过N个指
令进行计算所得到的结果。
Sample Input
5 1 6
+ 5
- 3
* 2
- 7
@ 2
3
2
1
5
Sample Output
5
3
6
HINT
1<=N,Q<= 105 ,1<=L<= Xk <=R<= 109 ,1<=a<= 109
题解
要对全部的数进行操作,还得改变一些溢出数。
我们可以发现,这些操作并不会改变输入的数的相对大小,所以我们可以先排一遍序,这样就保证了溢出的数是连续的一段,就可以用线段树来维护这个序列。
再维护溢出的数时,如果发现某一个区间的最小值比R还大,就代表要把这个区间更新为R。同样的,如果发现某一个区间的最大值比L还小,就改成L。
小(hei)技(ke)巧(ji):我们可以不用再新建一个标记来改值,就只要把乘法标记变为0,再把加法标记变成要要变的值就行。
本入代码奇丑无比,不喜勿喷
#include <cstdio>
#include <iostream>
#include <cmath>
#include <stack>
#include <algorithm>
#include <cstring>
#include <climits>
#define MAXN 100000+10
#define LL long long
using namespace std;
int n,m,maxd;
LL mi[MAXN<<2],mx[MAXN<<2],add[MAXN<<2],times[MAXN<<2],add2[MAXN<<2];
LL lm,rm;
struct Op{
LL op,d;
}op[MAXN];
struct Date{
LL d,n;
}a[MAXN];
bool cmp1(const Date a,const Date b) {return a.d<b.d;}
bool cmp2(const Date a,const Date b) {return a.n<b.n;}
void pushup(int rt)
{
mi[rt]=min(mi[rt<<1],mi[rt<<1|1]);
mx[rt]=max(mx[rt<<1],mx[rt<<1|1]);
}
void pushdown(int rt,int l,int r)
{
if(add[rt]||times[rt]!=1||add2[rt])
{
int m=(l+r)>>1;
mi[rt<<1]=(mi[rt<<1]*times[rt]+add[rt]+add2[rt]*a[l].d);
mi[rt<<1|1]=(mi[rt<<1|1]*times[rt]+add[rt]+add2[rt]*a[m+1].d);
mx[rt<<1]=(mx[rt<<1]*times[rt]+add[rt]+add2[rt]*a[m].d);
mx[rt<<1|1]=(mx[rt<<1|1]*times[rt]+add[rt]+add2[rt]*a[r].d);
add[rt<<1]=(add[rt<<1]*times[rt]+add[rt]);
add[rt<<1|1]=(add[rt<<1|1]*times[rt]+add[rt]);
add2[rt<<1]=(add2[rt<<1]*times[rt]+add2[rt]);
add2[rt<<1|1]=(add2[rt<<1|1]*times[rt]+add2[rt]);
times[rt<<1]=(times[rt]*times[rt<<1]);
times[rt<<1|1]=(times[rt]*times[rt<<1|1]);
times[rt]=1;add[rt]=0;add2[rt]=0;
}
}
void build(int rt,int l,int r)
{
if(l==r)
{
mi[rt]=mx[rt]=a[l].d;
maxd=max(maxd,rt);
return ;
}
int m=(l+r)>>1;
build(rt<<1,l,m);
build(rt<<1|1,m+1,r);
pushup(rt);
}
void Add(int L,int R,LL x,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
mi[rt]+=x;
mx[rt]+=x;
add[rt]=add[rt]+x;
return ;
}
int m=(l+r)>>1;
pushdown(rt,l,r);
if(L<=m) Add(L,R,x,l,m,rt<<1);
if(R>m) Add(L,R,x,m+1,r,rt<<1|1);
pushup(rt);
}
void Add2(int L,int R,LL x,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
mi[rt]+=x*a[l].d;
mx[rt]+=x*a[r].d;
add2[rt]=add2[rt]+x;
return ;
}
int m=(l+r)>>1;
pushdown(rt,l,r);
if(L<=m) Add(L,R,x,l,m,rt<<1);
if(R>m) Add(L,R,x,m+1,r,rt<<1|1);
pushup(rt);
}
void Mui(int L,int R,LL x,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
mi[rt]*=x;
mx[rt]*=x;
add[rt]=(add[rt]*x);
add2[rt]=(add2[rt]*x);
times[rt]=(x*times[rt]);
return ;
}
int m=(l+r)>>1;
pushdown(rt,l,r);
if(L<=m) Mui(L,R,x,l,m,rt<<1);
if(R>m) Mui(L,R,x,m+1,r,rt<<1|1);
pushup(rt);
}
void fixed(int L,int R,int l,int r,int rt)
{
if(lm<=mi[rt]&&mx[rt]<=rm) return ;
if(mx[rt]<lm)
{
mi[rt]=mx[rt]=add[rt]=lm;
add2[rt]=times[rt]=0;
return;
}else
if(mi[rt]>rm)
{
mi[rt]=mx[rt]=add[rt]=rm;
add2[rt]=times[rt]=0;
return ;
}
if(l==r) return ;
int m=(l+r)>>1;
pushdown(rt,l,r);
if(L<=m) fixed(L,R,l,m,rt<<1);
if(R>m) fixed(L,R,m+1,r,rt<<1|1);
pushup(rt);
}
LL query(int p,int l,int r,int rt)
{
if(l==r&&l==p)
return mi[rt];
int m=(l+r)>>1;LL ans=0;
pushdown(rt,l,r);
if(p<=m) ans=query(p,l,m,rt<<1);
else
if(p>m) ans=query(p,m+1,r,rt<<1|1);
return ans;
}
int main()
{
scanf("%d%lld%lld",&m,&lm,&rm);
for(int i=1;i<=m;i++)
{
char k[3];
scanf("%s%lld",k,&op[i].d);
if(k[0]=='+') op[i].op=1;
else if(k[0]=='-') op[i].op=2;
else if(k[0]=='*') op[i].op=3;
else if(k[0]=='@') op[i].op=4;
}
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i].d);
times[i]=times[i+n]=times[i+n*2]=times[i+n*3]=1;
a[i].n=i;
}
sort(a+1,a+n+1,cmp1);
build(1,1,n);
for(int i=1;i<=m;i++)
{
if(op[i].op==1) {Add(1,n,op[i].d,1,n,1);}
else if(op[i].op==2) {Add(1,n,-op[i].d,1,n,1);}
else if(op[i].op==3) {Mui(1,n,op[i].d,1,n,1);}
else if(op[i].op==4) {Add2(1,n,op[i].d,1,n,1);}
fixed(1,n,1,n,1);
}
for(int i=1;i<=n;i++)
a[i].d=query(i,1,n,1);
sort(a+1,a+n+1,cmp2);
for(int i=1;i<=n;i++)
printf("%lld\n",a[i].d);
return 0;
}