线段树维护区间开方/除法

Posted zijinjun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树维护区间开方/除法相关的知识,希望对你有一定的参考价值。

今天考试考了一些神仙数据结构

T1 线段树维护区间加,区间开方,区间和

(数据范围:5e5)

T2 线段树维护区间加,区间除,区间和,区间最值

对于这些题目,就像是之前考的区间与,区间或一样,除法,开方的操作会让各个数字之间越来越相近,最后变成一串一串连续的数字都是一样的,所以对于这一部分的操作我们一定程度上使用暴力,而如果一段都相等就相当于直接进行区间剪发的操作

那么我们来看如何判断区间一段都相等,那我们只需要维护区间的最值,最小值==最大值就完全相等了

然后.....代码.....被 \(yurzhang\) 神犇卡常,然后 \(huyufeifei\) 巨佬把我的 \(T1\) 改的面目全非......

为了大常数的尊严 ,还是放被卡常的代码

#include <bits/stdc++.h>

using namespace std;

#define ll long long
#define re register
#define gc getchar()
inline ll read()

    re char c(gc);re ll x(0);
    while(c<'0'||c>'9') c=gc;
    while(c>='0'&&c<='9') x=x*10+c-48,c=gc;
    return x;


const int N=5e5+10;

ll a[N],s[N<<2],minn[N<<2],maxx[N<<2],add[N<<2];

#define mid ((l+r)>>1)
#define ls id<<1
#define rs id<<1|1

inline void pushup(int id)

    s[id]=s[ls]+s[rs];
    minn[id]=min(minn[ls],minn[rs]);
    maxx[id]=max(maxx[ls],maxx[rs]);
 
inline void pushdown(int id,int l,int r)

    if(add[id]!=0)
    
        re int lx=mid-l+1,rx=r-mid;
        add[ls]+=add[id];
        add[rs]+=add[id];
        s[ls]+=add[id]*lx;
        s[rs]+=add[id]*rx;
        minn[rs]+=add[id];
        minn[ls]+=add[id];
        maxx[ls]+=add[id];
        maxx[rs]+=add[id];
        add[id]=0;
    

void built(int id,int l,int r)

    if(l==r)
    
        s[id]=a[l];
        minn[id]=a[l];
        maxx[id]=a[l];
        return ;
     
    built (ls,l,mid);
    built (rs,mid+1,r);
    pushup(id);

void change(int id,int l,int r,int L,int R,ll x)

    if(l>=L&&r<=R)
    
        s[id]+=x*(r-l+1);
        add[id]+=x;
        minn[id]+=x;
        maxx[id]+=x;
        return;
    
    pushdown(id,l,r);
    if(mid>=L) change(ls,l,mid,L,R,x);
    if(mid<R) change(rs,mid+1,r,L,R,x);
    pushup(id);

void Change(int id,int l,int r,int L,int R)

    if(l>=L&&r<=R&&floor(sqrt(maxx[id]))-maxx[id]==floor(sqrt(minn[id]))-minn[id])
    
        ll d=floor(sqrt(maxx[id]))-maxx[id];
//      cout<<maxx[id]<<' '<<d<<endl; 
        add[id]+=d;
        maxx[id]+=d;
        minn[id]+=d;
        s[id]+=d*(r-l+1);
        return;
    
    pushdown(id,l,r);
    if(L<=mid) Change(ls,l,mid,L,R);
    if(mid<R) Change(rs,mid+1,r,L,R);
    pushup(id);

ll query(int id,int l,int r,int L,int R)

    if(l>=L&&r<=R) return s[id];
    pushdown(id,l,r);
    ll ans=0;
    if(L<=mid) ans+=query(ls,l,mid,L,R);
    if(R>mid) ans+=query(rs,mid+1,r,L,R);
    return ans;


int n,m;

int main()

    freopen("comp.in","r",stdin);
    freopen("comp.out","w",stdout);
    n=read(),m=read();
    for(int i=1;i<=n;++i) a[i]=read();
    built(1,1,n);
    while(m--)
    
        int op=read(),l=read(),r=read();
        if(op==1) ll x=read();change(1,1,n,l,r,x);
        if(op==2) cout<<query(1,1,n,l,r)<<endl;
        if(op==3) Change(1,1,n,l,r); 
    
    return 0;
#include <bits/stdc++.h>

using namespace std;

#define re register
#define gc getchar()
inline int read()

    re char c(gc);re int x(0);
    while(c<'0'||c>'9') c=gc;
    while(c>='0'&&c<='9') x=x*10+c-48,c=gc;
    return x;


#define ll long long
const int N=1e5+10;

ll a[N],s[N<<2],minn[N<<2],maxx[N<<2],add[N<<2];

#define mid ((l+r)>>1)
#define ls id<<1
#define rs id<<1|1

inline void pushup(int id)

    s[id]=s[ls]+s[rs];
    minn[id]=min(minn[ls],minn[rs]);
    maxx[id]=max(maxx[ls],maxx[rs]);
 
inline void pushdown(int id,int l,int r)

    if(add[id]!=0)
    
        re int lx=mid-l+1,rx=r-mid;
        add[ls]+=add[id];
        add[rs]+=add[id];
        s[ls]+=add[id]*lx;
        s[rs]+=add[id]*rx;
        minn[rs]+=add[id];
        minn[ls]+=add[id];
        maxx[ls]+=add[id];
        maxx[rs]+=add[id];
        add[id]=0;
    

void built(int id,int l,int r)

    if(l==r)
    
        s[id]=a[l];
        minn[id]=a[l];
        maxx[id]=a[l];
        return ;
     
    built (ls,l,mid);
    built (rs,mid+1,r);
    pushup(id);

void change(int id,int l,int r,int L,int R,ll x)

    if(l>=L&&r<=R)
    
        s[id]+=x*(r-l+1);
        add[id]+=x;
        minn[id]+=x;
        maxx[id]+=x;
        return;
    
    pushdown(id,l,r);
    if(mid>=L) change(ls,l,mid,L,R,x);
    if(mid<R) change(rs,mid+1,r,L,R,x);
    pushup(id);

void Change(int id,int l,int r,int L,int R,ll x)

    if (l >=L&&r<=R&&maxx[id]-floor(maxx[id]/x)==minn[id]-floor(minn[id]/x))
    
        ll d=floor(maxx[id]/x)-maxx[id];
        add[id]+=d;
        maxx[id]+=d;
        minn[id]+=d;
        s[id]+=d*(r-l+1);
        return;
    
    pushdown(id,l,r);
    if(L<=mid) Change(ls,l,mid,L,R,x);
    if(mid<R) Change(rs,mid+1,r,L,R,x);
    pushup(id);

ll query(int id,int l,int r,int L,int R)

    if(l>=L&&r<=R) return s[id];
    pushdown(id,l,r);
    ll ans=0;
    if(L<=mid) ans+=query(ls,l,mid,L,R);
    if(R>mid) ans+=query(rs,mid+1,r,L,R);
    return ans;

ll Query(int id,int l,int r,int L,int R)

    if(l>=L&&r<=R) return maxx[id];
    pushdown(id,l,r);
    ll ans=0;
    if(L<=mid) ans=max(ans,Query(ls,l,mid,L,R));
    if(R>mid) ans=max(ans,Query(rs,mid+1,r,L,R));
    return ans;


int n,m;

int main()

    freopen("count.in","r",stdin);
    freopen("count.out","w",stdout);
    n=read(),m=read();
    for(int i=1;i<=n;++i) a[i]=read();
    built(1,1,n);
    while(m--)
    
        int op=read();
        ll l=read(),r=read();
        if(op==1) int x=read();change(1,1,n,l,r,x);
        if(op==2) cout<<query(1,1,n,l,r)<<endl;
        if(op==3) cout<<Query(1,1,n,l,r)<<endl;
        if(op==4) int x=read();Change(1,1,n,l,r,x);
    
    return 0;

以上是关于线段树维护区间开方/除法的主要内容,如果未能解决你的问题,请参考以下文章

花神游历各国 题解(小清新线段树/树状数组+并查集)

树链剖分

Tunnel Warfare(线段树 开方修改+剪枝优化

CCF(除法):线段树区间修改(50分)+线段树点修改(100分)+线段树(100分)

SP2713 GSS4 - Can you answer these queries IV(线段树)

HDU 4027 Can you answer these queries?(线段树区间开方)