「雅禮集訓 2017 Day1」市場 (線段樹除法,區間最小,區間查詢)

老師說,你們暴力求除法也整不了多少次就歸一了,暴力就好了(應該只有log(n)次)
於是暴力啊暴力,結果我歸天了。
好吧,在各種題解的摧殘下,我終於出了一篇巨好看(chou lou)代碼(很多結構體黨嫌醜)
#題意
那麼具體除法怎麼實現就是關鍵了
對於單個點或者區間內的數完全相同的區間,可以做成區間減法
因爲除法會使數變小,而相同的數減小的量是相同的,

那麼怎麼判斷區間內的數是否完全相同呢?

可以維護一個區間最小與區間最大,如果一個區間內最小數等於最大數,那麼顯然這個區間內所有數相等
區間最小與區間最大就不用說了吧?
然後暴力一波

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll sum[400101]={0}, minn[400101],maxx[400001]={0},add[400101]={0},a[401001];
int n,m;
void pushup(ll rt){
    sum[rt]=sum[rt<<1|1]+sum[rt<<1];
    minn[rt]=min(minn[rt<<1],minn[rt<<1|1]);
    maxx[rt]=max(maxx[rt<<1],maxx[rt<<1|1]);
}
inline ll Div(ll x, ll y) {//從樣例分析出這道題是向下取整的除法
    return floor((double)x/y);
}
void build(ll l,ll r,ll rt){
    if(l==r){
        sum[rt]=a[l];
        minn[rt]=a[l];
        maxx[rt]=a[l];
        return ;
    }
    long long mid=(l+r)>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    pushup(rt);
}
void pushdown(ll rt,ll ln,ll rn){
    if(add[rt]!=0){
        add[rt<<1]+=add[rt];
        add[rt<<1|1]+=add[rt];
        sum[rt<<1]+=add[rt]*ln;
        sum[rt<<1|1]+=add[rt]*rn;
        minn[rt<<1]+=add[rt];
        minn[rt<<1|1]+=add[rt];
        maxx[rt<<1]+=add[rt];
        maxx[rt<<1|1]+=add[rt];
        add[rt]=0;
    }
}
void update1(ll l,ll r,ll c,ll L,ll R,ll rt){
    if(l>=L&&r<=R){
        sum[rt]+=c*(r-l+1);
        add[rt]+=c;minn[rt]+=c;maxx[rt]+=c;
        return ;
    }
    ll mid=(l+r)>>1;
    pushdown(rt,mid-l+1,r-mid);
    if(L<=mid)update1(l,mid,c,L,R,rt<<1);
    if(R>mid)update1(mid+1,r,c,L,R,rt<<1|1);
    pushup(rt);
}
void update2(ll l,ll r,ll c,ll L,ll R,ll rt){//對於除法的暴力操作
     if (l >=L&&r<=R&&maxx[rt]-Div(maxx[rt],c)==minn[rt]-Div(minn[rt],c)){
        ll D=Div(maxx[rt],c)-maxx[rt];
        add[rt]+=D;maxx[rt]+=D;minn[rt]+=D;
        sum[rt]+=D*(r-l+1);
        return;
    }
    ll mid=(l+r)>>1;
    pushdown(rt,mid-l+1,r-mid);
    if(L<=mid)update2(l,mid,c,L,R,rt<<1);
    if(mid<R)update2(mid+1,r,c,L,R,rt<<1|1);
    pushup(rt);
}
ll query1(ll l,ll r,ll L,ll R,ll rt){
    if(l>=L&&r<=R){
        return sum[rt];
    }
    ll mid=(l+r)>>1;
    ll ans=0;
    pushdown(rt,mid-l+1,r-mid);
    if(L<=mid)ans+=query1(l,mid,L,R,rt<<1);
    if(R>mid)ans+=query1(mid+1,r,L,R,rt<<1|1);
    return ans;
}
ll query2(ll l,ll r,ll L,ll R,ll rt){
    if(l>=L&&r<=R){
        return minn[rt];
    }
    ll mid=(l+r)>>1;
    ll ans=1e18;
    pushdown(rt,mid-l+1,r-mid);
    if(L<=mid)ans=min(ans,query2(l,mid,L,R,rt<<1));
    if(R>mid)ans=min(ans,query2(mid+1,r,L,R,rt<<1|1));
    return ans;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)scanf("%lld",&a[i]);
    //memset(flag,1,sizeof(flag));
    build(0,n-1,1);
    while(m--){
        long long c,x,y,k;
        scanf("%lld%lld%lld",&c,&x,&y);
        if(c==1){scanf("%lld",&k);update1(0,n-1,k,x,y,1);}
        if(c==2){scanf("%lld",&k);update2(0,n-1,k,x,y,1);}
        if(c==4)printf("%lld\n",query1(0,n-1,x,y,1));
        if(c==3)printf("%lld\n",query2(0,n-1,x,y,1));
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章