[题解]LOJ_6029市场(线段树区间加/除

https://www.cnblogs.com/scx2015noip-as-php/p/loj6029.html

一开始以为裸的区间除,维护这一段是否全为0,后来发现还有加法,这样就会被卡了

这题除数达到了1e9,题解说在数很小除数很大的时候区间除会变成区间减,如一段序列由$x,x-1$组成,除一个$d$相当于减去了同样的变化量

所以我们需要维护区间最大最小值,每次判断最大值和最小值除完之后差是否一样,不一样递归

(我自己反正想不出来)

#include<bits/stdc++.h>
#define ls (x<<1)
#define rs (x<<1|1)
#define mid ((l+r)>>1)
#define ll long long
using namespace std;
const int maxn=100009;
int n,m;
struct node{
    ll sum,mn,tg,mx;//是否没除到0 
}t[maxn<<2];
inline ll min(ll a,ll b){return a<b?a:b;}
inline ll max(ll a,ll b){return a>b?a:b;}
inline void upd(int x){
    t[x].mn=min(t[ls].mn,t[rs].mn);
    t[x].mx=max(t[ls].mx,t[rs].mx);
    t[x].sum=t[ls].sum+t[rs].sum;
}
void build(int x,int l,int r){
    if(l==r){
        scanf("%lld",&t[x].sum);
        t[x].mx=t[x].mn=t[x].sum;
        return;
    }
    build(ls,l,mid);build(rs,mid+1,r);
    upd(x);
}
inline void pd(int x,int l,int r){
    if(t[x].tg){
        t[ls].tg+=t[x].tg;
        t[rs].tg+=t[x].tg;
        t[ls].sum+=t[x].tg*(mid-l+1);
        t[rs].sum+=t[x].tg*(r-mid);
        t[ls].mn+=t[x].tg;
        t[rs].mn+=t[x].tg;
        t[ls].mx+=t[x].tg;
        t[rs].mx+=t[x].tg;
        t[x].tg=0;
    }
}
void changea(int x,int l,int r,int L,int R,ll k){
    if(L<=l && r<=R){
        t[x].tg+=k;
        t[x].sum+=k*(r-l+1);
        t[x].mn+=k;t[x].mx+=k;
        return;
    }
    pd(x,l,r);
    if(L<=mid)changea(ls,l,mid,L,R,k);
    if(R>mid)changea(rs,mid+1,r,L,R,k);
    upd(x);
}
void changeb(int x,int l,int r,int L,int R,ll d){
    if(L<=l && r<=R){
        ll d1=t[x].mx-floor((double)t[x].mx/d),
        d2=t[x].mn-floor((double)t[x].mn/d);
        //转化为区间减 
        if(d1==d2){
            t[x].tg-=d1,t[x].sum-=d1*(r-l+1);
            t[x].mx-=d1,t[x].mn-=d1;
            return;
        }
    }
    pd(x,l,r);
    if(L<=mid)changeb(ls,l,mid,L,R,d);
    if(R>mid)changeb(rs,mid+1,r,L,R,d);
    upd(x);
}
ll querys(int x,int l,int r,int L,int R){
    if(L<=l && r<=R)return t[x].sum;
    pd(x,l,r);
    ll ans=0;
    if(L<=mid)ans+=querys(ls,l,mid,L,R);
    if(R>mid)ans+=querys(rs,mid+1,r,L,R);
    return ans;
}
ll querym(int x,int l,int r,int L,int R){
    if(L<=l && r<=R)return t[x].mn;
    pd(x,l,r);
    ll ans=1e18;
    if(L<=mid)ans=min(ans,querym(ls,l,mid,L,R));
    if(R>mid)ans=min(ans,querym(rs,mid+1,r,L,R));
    return ans;
}
int main(){
    scanf("%d%d",&n,&m);
    build(1,1,n);ll l,r,d,op;
    for(int i=1;i<=m;i++){
        scanf("%d",&op);
        if(op==1){
            scanf("%lld%lld%lld",&l,&r,&d);
            l++,r++; 
            changea(1,1,n,l,r,d);
        }
        else if(op==2){
            scanf("%lld%lld%lld",&l,&r,&d);
            l++,r++;
            changeb(1,1,n,l,r,d);
        }
        else if(op==3){
            scanf("%d%d",&l,&r);l++,r++;
            printf("%lld\n",querym(1,1,n,l,r));
        }
        else {
            scanf("%d%d",&l,&r);l++,r++;
            printf("%lld\n",querys(1,1,n,l,r));
        }
    }
}

 

posted @ 2019-09-24 14:53  羊肉汤泡煎饼  阅读(254)  评论(0编辑  收藏  举报