Description
【故事背景】
JYY有个奇怪的计算器,有一天这个计算器坏了,JYY希望你能帮助他写一个程序来模拟这个计算器的运算。
【问题描述】
JYY的计算器可以执行N条预设好的指令。每次JYY向计算器输入一个正整数X,计算器就会以X作为初始值,接着依次执行预设的N条指令,最后把最终得出的结果返回给JYY。
每一条指令可以是以下四种指令之一:(这里a表示一个正整数。)
1、+a:表示将当前的结果加上a;
2、-a:表示将当前的结果减去a;
3、*a:表示将当前的结果乘以a;
4、@a:表示将当前的结果加上a*X(X是一开始JYY输入的数)。
计算器用于记录运算结果的变量的存储范围是有限的,所以每次运算结束之后会有计算结果溢出的问题。JYY的计算器中,存储每计算结果的变量只能存储L到R之间的正整数,如果一次指令执行过后,计算结果超过了R,那么计算器就会自动把结果变成R,然后再以R作为当前结果继续进行之后的计算。同理,如果运算结果小于L,计算器也会把结果变成L,再接着计算。
比如,假设计算器可以存储1到6之间的值,如果当前的计算结果是2,那么在执行+5操作之后,存储结果的变量中的值将会是6。虽然2+5的实际结果是7,但是由于7超过了存储范围的上界,所以结果就被自动更正成了上界大小,也就是6。JYY一共想在计算器上输入Q个值,他想知道这Q个值输入计算器之后,分别会得到什么结果呢?
Input
输入文件的第一行包含三个正整数,N,L和R;
第接下来N行,每行一个指令,每个指令如题述,由一个字符和一个正整
数组成,字符和正整数中间有一个空格隔开;
第N+2行包含一个整数Q,表示JYY希望输入的数的数量;
第接下来Q行每行一个正整数,第k个正整数Xk表示JYY在第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
【样例说明】
当JYY输入2时,计算器会进行5次运算,每一次运算之后得到的结果分
别是6(实际计算结果为7但是超过了上界),3,6,1(实际结果为-1但是低于了下界)和5(由于一开始输入的是2,所以这一次计算为1+2×2)。
1<=N,Q<=10^5,1<=L<=Xk<=R<=10^9,1<=a<=10^9
Solution
将所有数排序之后用一个线段树统一操作,可以知道这些操作都不改变单调性,所以每次操作完之后就在线段树上二分溢出的部分,然后区间赋值即可。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
template<typename T>inline void read(T &x){
T f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(x=0;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
x*=f;
}
typedef long long LL;
const int maxn=100010;
struct Tag{
LL x,y;
Tag():x(1),y(0){}
Tag(LL a,LL b){
x=a;y=b;
}
bool exist(){
return x!=1||y;
}
Tag operator+=(Tag b){
x*=b.x;y=y*b.x+b.y;
return *this;
}
};
void atag(LL &x,Tag t){
x=x*t.x+t.y;
}
int Lmax,Rmax;
int n,m,q,c[maxn],b[maxn],a[maxn];
LL ans[maxn];
char opt[maxn][10];
struct Segment_Tree{
#define lc x<<1
#define rc x<<1|1
int L[maxn<<2],R[maxn<<2];
LL lb[maxn<<2],rb[maxn<<2];
LL mx[maxn<<2],mi[maxn<<2],tt[maxn<<2];
Tag tag[maxn<<2];
Segment_Tree(){
memset(rb,0,sizeof rb);
memset(mx,0,sizeof mx);
memset(mi,0,sizeof mi);
memset(tt,0,sizeof tt);
}
void update(int x){
mx[x]=max(mx[lc],mx[rc]);
mi[x]=min(mi[lc],mi[rc]);
}
void Build(int x,int *aa,int l,int r){
tag[x].x=1;tag[x].y=0;
if((L[x]=l)==(R[x]=r))
return lb[x]=rb[x]=mx[x]=mi[x]=aa[l],void();
int mid=(l+r)>>1;
Build(lc,aa,l,mid);Build(rc,aa,mid+1,r);
update(x);lb[x]=lb[lc];rb[x]=rb[rc];
}
void pushtag(int x,Tag t){
atag(mx[x],t);
atag(mi[x],t);
tag[x]+=t;
tt[x]*=t.x;
}
void pushtt(int x,LL val){
tt[x]+=val;
mx[x]+=rb[x]*val;
mi[x]+=lb[x]*val;
}
void pushdown(int x){
if(tag[x].exist()){
pushtag(lc,tag[x]);
pushtag(rc,tag[x]);
tag[x].x=1;tag[x].y=0;
}
if(tt[x]){
pushtt(lc,tt[x]);
pushtt(rc,tt[x]);
tt[x]=0;
}
}
void Modify(int x,int l,int r,Tag val){
if(L[x]>=l&&R[x]<=r){
pushtag(x,val);
return;
}
pushdown(x);
int mid=(L[x]+R[x])>>1;
if(l<=mid)Modify(lc,l,r,val);
if(r>mid)Modify(rc,l,r,val);
update(x);
}
int lower_bound(LL val){
if(mx[1]<val)return q+1;
int x=1;
while(L[x]!=R[x]){
pushdown(x);
if(mx[lc]>=val)x=lc;
else x=rc;
}
return L[x];
}
void Fixup(){
if(mx[1]>Rmax)Modify(1,lower_bound(Rmax-1),q,Tag{0,Rmax});
if(mi[1]<Lmax)Modify(1,1,lower_bound(Lmax)-1,Tag{0,Lmax});
}
LL Query(int x,int pos){
if(L[x]==R[x])return mx[x];
int mid=(L[x]+R[x])>>1;
pushdown(x);
if(pos<=mid)return Query(lc,pos);
else return Query(rc,pos);
}
}tree;
int main(){
read(n);read(Lmax);read(Rmax);
for(int i=1;i<=n;i++)
scanf("%s%d",opt[i],&c[i]);
read(q);
for(int i=1;i<=q;i++)read(a[i]),b[i]=a[i];
sort(b+1,b+q+1);int qq=q;
q=unique(b+1,b+q+1)-b-1;
tree.Build(1,b,1,q);
for(int i=1;i<=n;i++){
if(opt[i][0]=='+')tree.pushtag(1,Tag{1,c[i]});
else if(opt[i][0]=='-')tree.pushtag(1,Tag{1,-c[i]});
else if(opt[i][0]=='*')tree.pushtag(1,Tag{c[i],0});
else if(opt[i][0]=='@')tree.pushtt(1,c[i]);
tree.Fixup();
}
for(int i=1;i<=qq;i++)
printf("%lld\n",tree.Query(1,lower_bound(b+1,b+q+1,a[i])-b));
return 0;
}