「雅礼集训 2017 Day1」市场(线段树维护区间除)
输入
第一行为两个空格隔开的整数 n,q 分别表示商贩个数和政令 + 询问个数。
第二行包含 n 个由空格隔开的整数 a0∼an−1
接下来 q 行,每行表示一个操作,第一个数表示操作编号 1∼4 ,接下来的输入和问题描述一致。
输出
对于每个 3、4 操作,输出询问答案。
样例输入
10 10
-5 -4 -3 -2 -1 0 1 2 3 4
1 0 4 1
1 5 9 1
2 0 9 3
3 0 9
4 0 9
3 0 1
4 2 3
3 4 5
4 6 7
3 8 9
样例输出
-2
-2
-2
-2
0
1
1
提示
数据范围与提示
对于 30%的数据,n,q≤10^3;
对于 60% 的数据,保证数据随机;
对于 100%的数据,1≤n,q≤10^5,0≤l≤r≤n−1, c∈[−10^4, 10^4], d∈[2,10^9]
其实这里的区间除操作挺简单的
类似于线段树的区间开方操作
因为这里只有区间加
所以整个数列最大的增加数也只有左右(由于初始值好像好多都超过了范围所以不开还是要爆)
由于区间除的区间的数每次至少减少一半,所以要不了次整个区间的数就都变为了
而且又只有区间加,还是可以做到次就变成了
当然如果每次真的强行强行每个数都除O(加上常数还是够呛
所以我们类似于开方
维护一个区间和
当时,区间除就相当于整个区间减去了一个
所以我们打一个减的标记就可以了
当然如果有区间乘就没法做了
注意有负数,还有序列是从~给出来的
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){
char ch=getchar();
int res=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
return res*f;
}
#define lc (u<<1)
#define rc ((u<<1)|1)
#define mid ((l+r)>>1)
const int N=100005;
int n,m,a[N],mx[N<<2],mn[N<<2],sum[N<<2],add[N<<2];
inline int down(int x,int y) {
return floor((double)x/y);
}
inline void pushup(int u){
sum[u]=sum[lc]+sum[rc];
mx[u]=max(mx[lc],mx[rc]);
mn[u]=min(mn[lc],mn[rc]);
}
inline void pushdown(int u,int l,int r){
if(!add[u])return;
mx[lc]+=add[u],mx[rc]+=add[u];
mn[lc]+=add[u],mn[rc]+=add[u];
add[lc]+=add[u],add[rc]+=add[u];
sum[lc]+=(mid-l+1)*add[u],sum[rc]+=(r-mid)*add[u];
add[u]=0;
}
inline void buildtree(int u,int l,int r){
if(l==r){
mx[u]=mn[u]=sum[u]=a[l];return;
}
buildtree(lc,l,mid);
buildtree(rc,mid+1,r);
pushup(u);
}
inline void update(int u,int l,int r,int st,int des,int k){
if(st<=l&&r<=des){
add[u]+=k,sum[u]+=(r-l+1)*k,mx[u]+=k,mn[u]+=k;return;
}
pushdown(u,l,r);
if(mid>=st)update(lc,l,mid,st,des,k);
if(mid<des)update(rc,mid+1,r,st,des,k);
pushup(u);
}
inline void updatec(int u,int l,int r,int st,int des,int k){
if(st<=l&&r<=des&&((mx[u]-down(mx[u],k))==(mn[u]-down(mn[u],k)))){
int del=down(mx[u],k)-mx[u];
add[u]+=del,sum[u]+=(r-l+1)*del,mx[u]+=del,mn[u]+=del;return;
}
pushdown(u,l,r);
if(mid>=st)updatec(lc,l,mid,st,des,k);
if(mid<des)updatec(rc,mid+1,r,st,des,k);
pushup(u);
}
inline int query(int u,int l,int r,int st,int des){
if(st<=l&&r<=des){
return mn[u];
}
int ans=1e18;
pushdown(u,l,r);
if(mid>=st)ans=min(ans,query(lc,l,mid,st,des));
if(mid<des)ans=min(ans,query(rc,mid+1,r,st,des));
pushup(u);
return ans;
}
inline int queryt(int u,int l,int r,int st,int des){
if(st<=l&&r<=des){
return sum[u];
}
int ans=0;
pushdown(u,l,r);
if(mid>=st)ans+=queryt(lc,l,mid,st,des);
if(mid<des)ans+=queryt(rc,mid+1,r,st,des);
pushup(u);
return ans;
}
signed main(){
n=read(),m=read();
for(int i=1;i<=n;i++)a[i]=read();
buildtree(1,1,n);
for(int i=1;i<=m;i++){
int op=read();
if(op==1){
int l=read()+1,r=read()+1,c=read();
update(1,1,n,l,r,c);
}
else if(op==2){
int l=read()+1,r=read()+1,k=read();
updatec(1,1,n,l,r,k);
}
else if(op==3){
int l=read()+1,r=read()+1;
cout<<query(1,1,n,l,r)<<'\n';
}
else if(op==4){
int l=read()+1,r=read()+1;
cout<<queryt(1,1,n,l,r)<<'\n';
}
}
}