BZOJ3878 [Ahoi2014]奇怪的计算器 线段树
来源:互联网 发布:大学取消事业编制 知乎 编辑:程序博客网 时间:2024/06/05 02:02
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@ 23215
Sample Output
536
HINT
1<=N,Q<=
题解
要对全部的数进行操作,还得改变一些溢出数。
我们可以发现,这些操作并不会改变输入的数的相对大小,所以我们可以先排一遍序,这样就保证了溢出的数是连续的一段,就可以用线段树来维护这个序列。
再维护溢出的数时,如果发现某一个区间的最小值比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 longusing 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;}
0 0
- 【BZOJ3878】[Ahoi2014]奇怪的计算器【线段树】
- 【bzoj3878】【AHOI2014】【奇怪的计算器】【线段树】
- BZOJ3878 [Ahoi2014]奇怪的计算器 线段树
- 【BZOJ3878】【Ahoi2014】奇怪的计算器 维护区间性质。线段树
- bzoj3878 [Ahoi2014]奇怪的计算器
- [题解]bzoj3878 AHOI2014 奇怪的计算器
- 【线段树】[BZOJ3787][AHOI2014]奇怪的计算器
- [bzoj3878]奇怪的计算器
- BZOJ 3878 Ahoi2014 奇怪的计算器 线段树
- bzoj 3878: [Ahoi2014]奇怪的计算器
- [Ahoi2014]奇怪的计算器 解题报告
- bzoj3441(线段树的奇怪题)
- HDU 4027——线段树加奇怪的lazy
- [下界最小流] UNR #1 奇怪的线段树
- UOJ#217. 【UNR #1】奇怪的线段树
- [2017纪中11-6]奇怪的队列 树状数组+二分/线段树
- 奇怪的树
- SSL2844 2017年11月8日提高组T2 奇怪的队列(线段树贪心)
- JS深入之趣味比较隐式转换(一)
- 51nod 1073 约瑟夫环(递推)
- 二叉树的后序遍历
- nyoj 20 吝啬的国度 (dfs)
- 鸟哥的Linux私房菜笔记一
- BZOJ3878 [Ahoi2014]奇怪的计算器 线段树
- Hibernate学习笔记(第三天)
- 解读Batch Normalization
- jstl 数字转换成字符串
- 覆盖技术,虚拟技术,并行技术,缓冲技术
- DSP 实验一(CCS操作实验)
- 类库简介
- day05_dom4j
- 关于闭包