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<=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 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
原创粉丝点击