BZOJ3878: [Ahoi2014&Jsoi2014]奇怪的计算器
BZOJ3878: [Ahoi2014&Jsoi2014]奇怪的计算器
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
+ 5
- 3
* 2
- 7
@ 2
3
2
1
5
Sample Output
5
3
6
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
题解Here!
拿道题,二话不说一个 namespace 开码大暴力,40分,还是不少的。。。
然后就不会了。。。
正解是线段树。
将这 q 个数建立一颗线段树,四个操作都可以在线段树上完成。
因为四个操作都是线性的,溢出不会反转两个数的大小关系
那么我们可以预先将 q 个数排序,那么溢出的数一定是连续的两段,区间修改就行了
至于怎么找两端溢出的区间,每个节点维护一个区间最大值和最小值就好。
还有,赋值标记可以变为:乘法标记=0,加法标记=要赋的值。
注意一下 long long 的问题。。。
附代码:
#include<iostream> #include<algorithm> #include<cstdio> #define LSON rt<<1 #define RSON rt<<1|1 #define MAX(x) b[x].data1 #define MIN(x) b[x].data2 #define ADD(x) b[x].c #define MUL(x) b[x].d #define SIGN(x) b[x].e #define LSIDE(x) b[x].l #define RSIDE(x) b[x].r #define WIDTH(x) (RSIDE(x)-LSIDE(x)+1) #define MAXN 100010 using namespace std; int n,m; long long L,R; long long ans[MAXN]; struct node{ int f; long long x; }a[MAXN],num[MAXN]; struct Segment_Tree{ long long data1,data2,c,d,e; int l,r; }b[MAXN<<2]; inline int read(){ int date=0,w=1;char c=0; while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();} return date*w; } inline int change(char ch){ switch(ch){ case '+':return 1; case '-':return 2; case '*':return 3; case '@':return 4; } } inline bool cmp(const node &x,const node &y){ return (x.x==y.x?x.f<y.f:x.x<y.x); } inline void pushup(int rt){ MAX(rt)=max(MAX(LSON),MAX(RSON)); MIN(rt)=min(MIN(LSON),MIN(RSON)); } inline void pushdown(int rt){ if(LSIDE(rt)==RSIDE(rt))return; int mid=LSIDE(rt)+RSIDE(rt)>>1; MAX(LSON)=MAX(LSON)*MUL(rt)+ADD(rt)+num[mid].x*SIGN(rt); MIN(LSON)=MIN(LSON)*MUL(rt)+ADD(rt)+num[LSIDE(rt)].x*SIGN(rt); MUL(LSON)*=MUL(rt); ADD(LSON)=ADD(LSON)*MUL(rt)+ADD(rt); SIGN(LSON)=SIGN(LSON)*MUL(rt)+SIGN(rt); MAX(RSON)=MAX(RSON)*MUL(rt)+ADD(rt)+num[RSIDE(rt)].x*SIGN(rt); MIN(RSON)=MIN(RSON)*MUL(rt)+ADD(rt)+num[mid+1].x*SIGN(rt); MUL(RSON)*=MUL(rt); ADD(RSON)=ADD(RSON)*MUL(rt)+ADD(rt); SIGN(RSON)=SIGN(RSON)*MUL(rt)+SIGN(rt); ADD(rt)=0;MUL(rt)=1;SIGN(rt)=0; } void buildtree(int l,int r,int rt){ int mid; LSIDE(rt)=l; RSIDE(rt)=r; ADD(rt)=0;MUL(rt)=1;SIGN(rt)=0; if(l==r){ MAX(rt)=MIN(rt)=num[l].x; return; } mid=l+r>>1; buildtree(l,mid,LSON); buildtree(mid+1,r,RSON); pushup(rt); } void update_add(int l,int r,long long c,int rt){ int mid; if(l<=LSIDE(rt)&&RSIDE(rt)<=r){ MAX(rt)+=c;MIN(rt)+=c; ADD(rt)+=c; return; } pushdown(rt); mid=LSIDE(rt)+RSIDE(rt)>>1; if(l<=mid)update_add(l,r,c,LSON); if(mid<r)update_add(l,r,c,RSON); pushup(rt); } void update_mul(int l,int r,long long c,int rt){ int mid; if(l<=LSIDE(rt)&&RSIDE(rt)<=r){ MAX(rt)*=c;MIN(rt)*=c; MUL(rt)*=c;ADD(rt)*=c; return; } pushdown(rt); mid=LSIDE(rt)+RSIDE(rt)>>1; if(l<=mid)update_mul(l,r,c,LSON); if(mid<r)update_mul(l,r,c,RSON); pushup(rt); } void update_sign(int l,int r,long long c,int rt){ int mid; if(l<=LSIDE(rt)&&RSIDE(rt)<=r){ MAX(rt)+=c*num[RSIDE(rt)].x; MIN(rt)+=c*num[LSIDE(rt)].x; SIGN(rt)+=c; return; } pushdown(rt); mid=LSIDE(rt)+RSIDE(rt)>>1; if(l<=mid)update_sign(l,r,c,LSON); if(mid<r)update_sign(l,r,c,RSON); pushup(rt); } void update_num(int l,int r,int rt){ int mid; if(MAX(rt)<=R&&MIN(rt)>=L)return; else if(MAX(rt)<L&&MIN(rt)<L){ MAX(rt)=MIN(rt)=L; ADD(rt)=L;MUL(rt)=0;SIGN(rt)=0; return; } else if(MAX(rt)>R&&MIN(rt)>R){ MAX(rt)=MIN(rt)=R; ADD(rt)=R;MUL(rt)=0;SIGN(rt)=0; return; } pushdown(rt); mid=l+r>>1; update_num(l,mid,LSON); update_num(mid+1,r,RSON); pushup(rt); } void query(int l,int r,int rt){ int mid; if(LSIDE(rt)==RSIDE(rt)){ ans[num[l].f]=MIN(rt); return; } pushdown(rt); mid=l+r>>1; query(l,mid,LSON); query(mid+1,r,RSON); } void work(){ for(int i=1;i<=n;i++){ switch(a[i].f){ case 1:update_add(1,m,a[i].x,1);break; case 2:update_add(1,m,-a[i].x,1);break; case 3:update_mul(1,m,a[i].x,1);break; case 4:update_sign(1,m,a[i].x,1);break; } update_num(1,m,1); } query(1,m,1); for(int i=1;i<=m;i++)printf("%d\n",ans[i]); } void init(){ char ch[2]; n=read();L=read();R=read(); for(int i=1;i<=n;i++){ scanf("%s",ch); a[i].f=change(ch[0]); a[i].x=read(); } m=read(); for(int i=1;i<=m;i++){ num[i].x=read(); num[i].f=i; } sort(num+1,num+m+1,cmp); buildtree(1,m,1); } int main(){ init(); work(); return 0; }