题解 P4041 [AHOI2014/JSOI2014] 奇怪的计算器
洛谷。
题意
有 $Q$ 个询问,$n$ 个操作,一共有 4 种:
- $+a$:结果加上 $a$;
- $-a$:结果减去 $a$;
- $\times a$;结果乘上 $a$;
- $@a$:结果加上 $a\times X$($X$ 是一开始输入的数)。 将每个询问放在 $n$ 个操作中过一遍,同时每次处理完后,倘若小于 $L$,赋值为 $L$;倘若大于 $R$,赋值为 $R$。
暴力
按照题意模拟即可。
分析
我们可以发现,我们所有数的经历的过程是一样的,我们可以用线段树来维护我们的 6 中操作:
- 区间加;
- 区间减(同 1);
- 区间乘;
- 区间加的变种;
- 区间取至最大值;
- 区间取至最小值。
这么算来,我们似乎是要维护 5 种 tag,10 种值。
想想都让人头皮发麻,怎么都应该是黑题才对。
但是实际上,我们的其中操作其实并不会改变期间相邻数的大小关系,因此,我们的 5、6 操作就变成了区间覆盖与一个二分(找到最后一个小于 $L$ 或 第一个大于 $R$)啦。
总结一下,我们需要维护区间乘、区间加、区间加变形、区间覆盖、单点查询。
看起来还是非常复杂,但是我们用 $c_p\times tag1_p+tag2_p$ 的形式,就可以将区间乘,区间加,区间覆盖融为一体。
最后的区间加变种,地位与区间加等同,与区间加的维护大致相同。
struct SEG {
#define ls p<<1
#define rs p<<1|1
int c[N<<2],tag[N<<2],tag2[N<<2],tag3[N<<2];
inline void cl(int p,int x,int y,int L,int R) {
tag3[p]*=x;
tag2[p]=tag2[p]*x+y;
tag[p]=tag[p]*x;
}
inline void cl(int p,int x) {
tag3[p]+=x;
}
inline void pushdown(int p,int L,int R) {
int mid=L+R>>1;
cl(ls,tag[p],tag2[p],L,mid),cl(rs,tag[p],tag2[p],mid+1,R);
cl(ls,tag3[p]),cl(rs,tag3[p]);
tag[p]=1,tag2[p]=tag3[p]=0;
}
inline void build(int p,int L,int R) {
tag[p]=1,tag2[p]=tag3[p]=0;
if(L==R) {
c[p]=qu[L].x;
return ;
}
int mid=L+R>>1;
build(ls,L,mid),build(rs,mid+1,R);
}
inline void change(int p,int L,int R,int l,int r,int x,int y) {
if(l>r) return ;
if(l<=L&&R<=r) {
cl(p,x,y,L,R);
return ;
}
int mid=L+R>>1;
pushdown(p,L,R);
if(l<=mid) change(ls,L,mid,l,r,x,y);
if(mid<r) change(rs,mid+1,R,l,r,x,y);
}
inline void change(int p,int L,int R,int l,int r,int x) {
if(l>r) return ;
if(l<=L&&R<=r) {
cl(p,x);
return ;
}
int mid=L+R>>1;
pushdown(p,L,R);
if(l<=mid) change(ls,L,mid,l,r,x);
if(mid<r) change(rs,mid+1,R,l,r,x);
}
inline int query(int p,int L,int R,int x) {
if(L==R) return c[p]*tag[p]+tag2[p]+tag3[p]*c[p];
pushdown(p,L,R);
int mid=L+R>>1;
if(x<=mid) return query(ls,L,mid,x);
if(mid<x) return query(rs,mid+1,R,x);
}
#undef ls
#undef rs
} tree;
inline void solvel() {
int l=1,r=m,res=0;
while(l<=r) {
int mid=l+r>>1;
int x=tree.query(1,1,m,mid);
if(x<L) {
res=mid;
l=mid+1;
} else r=mid-1;
}
tree.change(1,1,m,1,res,0,L);
}
inline void solver() {
int l=1,r=m,res=m+1;
while(l<=r) {
int mid=l+r>>1;
int x=tree.query(1,1,m,mid);
if(x>R) {
res=mid;
r=mid-1;
} else l=mid+1;
}
tree.change(1,1,m,res,m,0,R);
}

浙公网安备 33010602011771号