【BZOJ3878】【AHOI2014&JSOI2014】奇怪的计算器

题面:传送门


    看起来很毒瘤的一道题。。。

    这道题做法的确不怎么明显,我们会发现,由于乘的数是正的,所以不论怎么样操作,原来输入的数的大小顺序不变。这样我们考虑离线。将所有数排完序后一个操作一个操作用线段树修改。区间修改当然得有懒标记啦,而且这道题还需要 3 3 个!分别记录乘的数,加的数和加的xk的个数。

    线段树维护两个值,区间最小值和区间最大值,直接修改没什么好说的,随便搞一搞就行。那怎么处理溢出问题呢?我们发现溢出一定出现在最左边和最右边,那么我们考虑二分加查询,这是 Θ(log22q) Θ ( l o g 2 2 q ) 的,如果将二分与线段树查询合并,就变成了 Θ(log2q) Θ ( l o g 2 q ) 的。线段树区间修改,单点查询均是 Θ(log2q) Θ ( l o g 2 q ) ,所以总的复杂度: Θ(nlog2q) Θ ( n l o g 2 q )

    是不是也不怎么难?

    我的代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
struct ele{
    int v,id;
    bool operator<(ele u)const
    {
        return v<u.v;
    }
};
ele a[100010];
long long L,R;
int n,q;
char buf[1010];
pair<int,long long>op[100010];
namespace sgt
{
    long long mx[200010],mn[200010],tomul[200010],toadd[200010],toalt[200010];
    int son[200010][2],root,cnt,lp[200010],rp[200010];
    void pushup(int x)
    {
        if(!son[x][0] || !son[x][1])return;
        mx[x]=mx[son[x][1]];
        mn[x]=mn[son[x][0]];
    }
    void pushdown(int x)
    {
        mx[x]*=tomul[x];
        mx[x]+=toadd[x];
        mx[x]+=1LL*a[rp[x]].v*toalt[x];
        mn[x]*=tomul[x];
        mn[x]+=toadd[x];
        mn[x]+=1LL*a[lp[x]].v*toalt[x];
        if(son[x][0] && son[x][1])
        {
            tomul[son[x][0]]*=tomul[x];
            toadd[son[x][0]]*=tomul[x];
            toalt[son[x][0]]*=tomul[x];
            toadd[son[x][0]]+=toadd[x];
            toalt[son[x][0]]+=toalt[x];
            tomul[son[x][1]]*=tomul[x];
            toadd[son[x][1]]*=tomul[x];
            toalt[son[x][1]]*=tomul[x];
            toadd[son[x][1]]+=toadd[x];
            toalt[son[x][1]]+=toalt[x];
        }
        tomul[x]=1;toadd[x]=toalt[x]=0;
    }
    void build(int &x,int l,int r)
    {
        x=++cnt;
        lp[x]=l;
        rp[x]=r;
        tomul[x]=1;
        if(l==r)
        {
            mx[x]=mn[x]=a[l].v;
            return;
        }
        int mid=(l+r)>>1;
        build(son[x][0],l,mid);
        build(son[x][1],mid+1,r);
        pushup(x);
    }
    void update(int a,int b,int k,int l,int r,long long mul,long long add,long long alt)
    {
        if(a>b)return;
        pushdown(k);
        if(a<=l && b>=r)
        {
            tomul[k]*=mul;
            toadd[k]*=mul;
            toalt[k]*=mul;
            toadd[k]+=add;
            toalt[k]+=alt;
            pushdown(k);
            return;
        }
        int mid=(l+r)>>1;
        pushdown(son[k][0]);
        pushdown(son[k][1]);
        if(b<=mid)update(a,b,son[k][0],l,mid,mul,add,alt);
        else if(a>mid)update(a,b,son[k][1],mid+1,r,mul,add,alt);
        else
        {
            update(a,mid,son[k][0],l,mid,mul,add,alt);
            update(mid+1,b,son[k][1],mid+1,r,mul,add,alt);
        }
        pushup(k);
    }
    void chgl(int x,int l,int r)
    {
        if(l>r)return;
        pushdown(x);
        if(l==r)
        {
            update(1,l,root,1,q,0,L,0);
            return;
        }
        int mid=(l+r)>>1;
        pushdown(son[x][1]);
        if(mn[son[x][1]]<L)chgl(son[x][1],mid+1,r);
        else chgl(son[x][0],l,mid);
    }
    void chgr(int x,int l,int r)
    {
        if(l>r)return;
        pushdown(x);
        if(l==r)
        {
            update(l,q,root,1,q,0,R,0);
            return;
        }
        int mid=(l+r)>>1;
        pushdown(son[x][0]);
        if(mx[son[x][0]]>R)chgr(son[x][0],l,mid);
        else chgr(son[x][1],mid+1,r);
    }
    long long query(int x,int l,int r,int v)
    {
        pushdown(x);
        if(l==r)return mn[x];
        int mid=(l+r)>>1;
        if(v<=mid)return query(son[x][0],l,mid,v);else return query(son[x][1],mid+1,r,v);
    }
}
long long ans[100010];
int main()
{
    scanf("%d%lld%lld",&n,&L,&R);
    for(int i=1;i<=n;i++)
    {
        long long x;
        scanf("%s%lld",buf,&x);
        if(buf[0]=='+')op[i]=make_pair(1,x);
        else if(buf[0]=='-')op[i]=make_pair(2,x);
        else if(buf[0]=='*')op[i]=make_pair(3,x);
        else op[i]=make_pair(4,x);
    }
    scanf("%d",&q);
    for(int i=1;i<=q;i++)
    {
        scanf("%d",&a[i].v);
        a[i].id=i;
    }
    sort(a+1,a+q+1);
    sgt::build(sgt::root,1,q);
    for(int i=1;i<=n;i++)
    {
        if(op[i].first==1)sgt::update(1,q,sgt::root,1,q,1,op[i].second,0);
        else if(op[i].first==2)sgt::update(1,q,sgt::root,1,q,1,-op[i].second,0);
        else if(op[i].first==3)sgt::update(1,q,sgt::root,1,q,op[i].second,0,0);
        else sgt::update(1,q,sgt::root,1,q,1,0,op[i].second);
        if(sgt::mn[sgt::root]<L)sgt::chgl(sgt::root,1,q);
        if(sgt::mx[sgt::root]>R)sgt::chgr(sgt::root,1,q);
    }
    for(int i=1;i<=q;i++)ans[a[i].id]=sgt::query(sgt::root,1,q,i);
    for(int i=1;i<=q;i++)printf("%lld\n",ans[i]);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值