以下说的相等指的是减小量相等,因为减小量相等就可以统一运算
本题其实就是道线段树裸题,
下去整操作可以装换为数字相等时的区间减法
关键是怎么算出时间复杂度
时间复杂度
因
为
每
次
除
数
至
少
为
2
,
所
以
一
个
数
最
多
除
l
o
g
次
因为每次除数至少为2,所以一个数最多除log次
因为每次除数至少为2,所以一个数最多除log次
由
于
存
在
加
法
,
所
以
不
能
直
接
说
明
只
能
l
o
g
次
。
由于存在加法,所以不能直接说明只能log次。
由于存在加法,所以不能直接说明只能log次。
若
最
大
值
小
于
除
数
,
则
全
变
为
0
,
l
o
g
次
操
作
后
一
个
区
间
就
会
相
等
,
加
法
又
会
使
l
o
g
个
区
间
不
相
等
,
所
以
使
n
个
区
间
相
等
的
复
杂
度
是
l
o
g
2
n
,
相
等
就
会
直
接
回
溯
,
这
就
保
证
了
时
间
复
杂
度
若最大值小于除数,则全变为0,log次操作后一个区间就会相等,加法又会使log个区间不相等,所以使n个区间相等的复杂度是log^2n,相等就会直接回溯,这就保证了时间复杂度
若最大值小于除数,则全变为0,log次操作后一个区间就会相等,加法又会使log个区间不相等,所以使n个区间相等的复杂度是log2n,相等就会直接回溯,这就保证了时间复杂度
每
一
次
在
线
段
树
上
的
操
作
最
坏
要
推
到
底
,
所
以
总
的
时
间
复
杂
度
是
n
l
o
g
2
n
每一次在线段树上的操作最坏要推到底,所以总的时间复杂度是nlog^2n
每一次在线段树上的操作最坏要推到底,所以总的时间复杂度是nlog2n
P.S:
- 判断区间是否全部想等只需要判断最值下取整的减小量是否相等,因为如果最值减小量相等的时候,最值的差为0或1,中间的数减小量也是相等的
- a/b是使绝对值下取整,有负数时,下取整应用floor
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100010;
int n,Q;
ll a[N];
struct tre{
ll tag,minx,maxx,sum;
ll flag;
}tree[N*4];
void push_up(int p){tree[p].maxx=max(tree[p<<1].maxx,tree[p<<1|1].maxx);tree[p].minx=min(tree[p<<1].minx,tree[p<<1|1].minx),tree[p].sum=tree[p<<1].sum+tree[p<<1|1].sum;}
void make_tree(int l,int r,int p){
if(l==r){tree[p].sum=a[l];tree[p].maxx=tree[p].minx=tree[p].sum;tree[p].flag=tree[p].maxx;return;}
int mid=(l+r)>>1;
make_tree(l,mid,p<<1);
make_tree(mid+1,r,p<<1|1);
push_up(p);
tree[p].flag=tree[p].maxx;
}
void push_down(int l,int r,int p){
if(!tree[p].tag) return;
int mid=(l+r)>>1;
tree[p<<1].sum+=1ll*(mid-l+1)*tree[p].tag;
tree[p<<1|1].sum+=1ll*(r-mid)*tree[p].tag;
tree[p<<1].maxx+=tree[p].tag;tree[p<<1|1].maxx+=tree[p].tag;tree[p<<1].minx+=tree[p].tag;tree[p<<1|1].minx+=tree[p].tag;
tree[p<<1].tag+=tree[p].tag;tree[p<<1|1].tag+=tree[p].tag;tree[p].tag=0;
}
void add(int l,int r,int p,int fs,int se,ll val){
if(fs<=l&&r<=se){
tree[p].sum+=1ll*(r-l+1)*val;
tree[p].maxx+=1ll*val,tree[p].minx+=1ll*val;
tree[p].tag+=val;
return;
}
push_down(l,r,p);
int mid=(l+r)>>1;
if(fs<=mid) add(l,mid,p<<1,fs,se,val);
if(se>mid) add(mid+1,r,p<<1|1,fs,se,val);
push_up(p);
}
ll divd(ll xx,ll yy){return floor((double)xx/yy);}//
void update(int l,int r,int p,int fs,int se,ll divide){
if(fs<=l&&r<=se&&((tree[p].maxx-divd(tree[p].maxx,divide))==((tree[p].minx-divd(tree[p].minx,divide))))){//
ll D=tree[p].maxx-divd(tree[p].maxx,divide);
tree[p].maxx-=D;tree[p].minx-=D;tree[p].sum-=1ll*D*(r-l+1);
tree[p].tag-=D;
return;
}
push_down(l,r,p);
int mid=(l+r)>>1;
if(fs<=mid) update(l,mid,p<<1,fs,se,divide);
if(se>mid) update(mid+1,r,p<<1|1,fs,se,divide);
push_up(p);
}
ll get_min(int l,int r,int p,int fs,int se){
if(fs<=l&&r<=se){
return tree[p].minx;
}
push_down(l,r,p);
int mid=(l+r)>>1;
ll ans=LLONG_MAX;
if(fs<=mid) ans=min(ans,get_min(l,mid,p<<1,fs,se));
if(se>mid) ans=min(ans,get_min(mid+1,r,p<<1|1,fs,se));
return ans;
}
ll get_sum(int l,int r,int p,int fs,int se){
ll ans=0;
if(fs<=l&&r<=se){
return tree[p].sum;
}
push_down(l,r,p);
int mid=(l+r)>>1;
if(fs<=mid) ans+=get_sum(l,mid,p<<1,fs,se);
if(se>mid) ans+=get_sum(mid+1,r,p<<1|1,fs,se);
return ans;
}
int main(){
scanf("%d%d",&n,&Q);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
make_tree(1,n,1);
while(Q--)
{
int tof;
scanf("%d",&tof);
if(tof==1){
int l,r;ll c;
scanf("%d%d%lld",&l,&r,&c);
add(1,n,1,l+1,r+1,c);
}
if(tof==2){
int l,r;ll d;
scanf("%d%d%lld",&l,&r,&d);
update(1,n,1,l+1,r+1,d);
}
if(tof==3){
int l,r;
scanf("%d%d",&l,&r);
ll ans=get_min(1,n,1,l+1,r+1);
printf("%lld\n",ans);
}
if(tof==4){
int l,r;
scanf("%d%d",&l,&r);
ll ans=get_sum(1,n,1,l+1,r+1);
printf("%lld\n",ans);
}
}
}