市场

37 篇文章 1 订阅
18 篇文章 0 订阅

市场

以下说的相等指的是减小量相等,因为减小量相等就可以统一运算

本题其实就是道线段树裸题,
下去整操作可以装换为数字相等时的区间减法
关键是怎么算出时间复杂度

时间复杂度

因 为 每 次 除 数 至 少 为 2 , 所 以 一 个 数 最 多 除 l o g 次 因为每次除数至少为2,所以一个数最多除log次 2log
由 于 存 在 加 法 , 所 以 不 能 直 接 说 明 只 能 l o g 次 。 由于存在加法,所以不能直接说明只能log次。 log
若 最 大 值 小 于 除 数 , 则 全 变 为 0 , l o g 次 操 作 后 一 个 区 间 就 会 相 等 , 加 法 又 会 使 l o g 个 区 间 不 相 等 , 所 以 使 n 个 区 间 相 等 的 复 杂 度 是 l o g 2 n , 相 等 就 会 直 接 回 溯 , 这 就 保 证 了 时 间 复 杂 度 若最大值小于除数,则全变为0,log次操作后一个区间就会相等,加法又会使log个区间不相等,所以使n个区间相等的复杂度是log^2n,相等就会直接回溯,这就保证了时间复杂度 0log使log,使nlog2n
每 一 次 在 线 段 树 上 的 操 作 最 坏 要 推 到 底 , 所 以 总 的 时 间 复 杂 度 是 n l o g 2 n 每一次在线段树上的操作最坏要推到底,所以总的时间复杂度是nlog^2n 线nlog2n

P.S:

  1. 判断区间是否全部想等只需要判断最值下取整的减小量是否相等,因为如果最值减小量相等的时候,最值的差为0或1,中间的数减小量也是相等的
  2. 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);
    	}
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值