BZOJ3878 AHOI2014 奇怪的计算器 线段树

题意:

给定N个操作,每种操作的格式为:

1、+a:表示将当前的结果加上a
2、-a:表示将当前的结果减去a
3、*a:表示将当前的结果乘以a
4、@a:表示将当前的结果加上a*X(X是一开始JYY输入的数)
在操作中,如果结果>R,则结果=R;如果结果<L,则结果=L。给定M个x i,求每个x在经过这N个操作之后的结果是多少

题解:

Orz wuyuhan

离散化之后线段树维护,由于修改后数相对大小并不变化,因此可以找到<=L和>=R开始的位置单独维护。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long

const int MAXN=100000+2;
int n,m,h[MAXN],p[MAXN];
ll SL,SR,L,R,s[MAXN],xx[MAXN];
struct tag{
    long long a,b,c;
    void clear(){ a=1,b=c=0;}
    void operator+=(tag o){ a=a*o.a,b=b*o.a+o.b,c=c*o.a+o.c;}
    long long calc(long long x){ return min(max(L,x*(a+b)+c),R);}
};
struct tree{
    tag l,r,la;
    tree(){l.clear(),r.clear(),la.clear();}
}t[3*MAXN];

bool cmp(int a,int b){ return xx[a]<xx[b];}

void down(int x,int l,int r){
    if(l>=r)return;
    t[x*2].la+=t[x].la,t[x*2].l+=t[x].la,t[x*2].r+=t[x].la;
    t[x*2+1].la+=t[x].la,t[x*2+1].l+=t[x].la,t[x*2+1].r+=t[x].la;
    t[x].la.clear();
}

void solve(int x,int l,int r){
    if(t[x].r.calc(xx[h[r]])!=R&&t[x].l.calc(xx[h[l]])!=L)return;

    down(x,l,r);
    if(t[x].l.calc(xx[h[l]])==R){t[x].l=t[x].r=t[x].la=(tag){0,0,R};return;}
    if(t[x].r.calc(xx[h[r]])==L){t[x].l=t[x].r=t[x].la=(tag){0,0,L};return;}

    solve(x*2,l,l+r>>1),solve(x*2+1,(l+r>>1)+1,r);
    t[x].l=t[x*2].l,t[x].r=t[x*2+1].r;
}

void solve2(int x,int l,int r){
    down(x,l,r);
    if(l!=r) solve2(x*2,l,l+r>>1),solve2(x*2+1,(l+r>>1)+1,r);
    else xx[h[l]]=t[x].l.calc(xx[h[l]]);
}

int main(){
    cin >> n >> L >> R;
    for(int i=1;i<=n;i++){
        char z[3];
        scanf("%s",z),cin >> s[i];

        if(z[0]=='+')p[i]=1;
        if(z[0]=='-')p[i]=2;
        if(z[0]=='*')p[i]=3;
        if(z[0]=='@')p[i]=4;
    }
    cin >> m;
    for(int i=1;i<=m;i++) cin >> xx[i],h[i]=i;
    sort(&h[1],&h[m+1],cmp);

    tag v;
    for(int i=1;i<=n;i++){
        if(p[i]==1)v=(tag){1,0,s[i]};
        if(p[i]==2)v=(tag){1,0,-s[i]};
        if(p[i]==3)v=(tag){s[i],0,0};
        if(p[i]==4)v=(tag){1,s[i],0};

        t[1].la+=v,t[1].l+=v,t[1].r+=v;
        solve(1,1,m);
    }

    solve2(1,1,m);
    for(int i=1;i<=m;i++) printf("%d\n",(int)xx[i]);

    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/WDZRMPCBIT/p/6444176.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值