题面:传送门
看起来很毒瘤的一道题。。。
这道题做法的确不怎么明显,我们会发现,由于乘的数是正的,所以不论怎么样操作,原来输入的数的大小顺序不变。这样我们考虑离线。将所有数排完序后一个操作一个操作用线段树修改。区间修改当然得有懒标记啦,而且这道题还需要 3 3 个!分别记录乘的数,加的数和加的的个数。
线段树维护两个值,区间最小值和区间最大值,直接修改没什么好说的,随便搞一搞就行。那怎么处理溢出问题呢?我们发现溢出一定出现在最左边和最右边,那么我们考虑二分加查询,这是 Θ(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;
}