zoukankan      html  css  js  c++  java
  • P3373 【模板】线段树 2

    线段是是一个很好用的数据结构,特别是在于长长的板子

    -----------------

    链接:Miku

    ----------------

    先来一份线段树1的代码

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    int n,m;
    long long sum[400005], lazy[400005];
    int f,x,y;
    long long k;
    void pushdown(int x, int L, int R){
        if (lazy[x] != 0){
            int mid = (L + R) >> 1;
            lazy[x << 1] += lazy[x];
            lazy[x << 1 | 1] += lazy[x];
            sum[x << 1] += lazy[x] * (mid - L + 1);
            sum[x << 1 | 1] += lazy[x] * (R - mid);
            lazy[x] = 0;
        }
        return;
    }
    void pushup(int x){
        sum[x] = sum[x << 1] + sum[x << 1 | 1];
        return;
    }
    void update(int x, int l, int r, int L, int R, long long d){
        if (L <= l && r <= R){
            lazy[x] += d;
            sum[x] += d * (r - l + 1);
            return;
        }
        int mid = (l + r) >> 1;
        pushdown(x, l, r);
        if (L <= mid) update(x << 1, l, mid, L, R, d);
        if (R > mid) update(x << 1 | 1, mid + 1, r, L, R, d);
        pushup(x);
    }
    long long query(int x, int l, int r, int L, int R){
        if (L <= l && r <= R){
            return sum[x];
        }
        int mid = (l + r) >> 1;
        pushdown(x, l, r);
        long long ans = 0;
        if (L <= mid) ans += query(x << 1, l, mid, L, R);
        if (R > mid) ans += query(x << 1 | 1, mid + 1, r, L, R);
        return ans;
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i){
            scanf("%d",&x);
            update(1, 1, n, i, i, x);
        }
        for(int i=1;i<=m;++i){
            scanf("%d",&f);
            if(f==1){
                scanf("%d%d%lld",&x,&y,&k);
                update(1, 1, n, x, y, k);
            }
            else{
                scanf("%d%d",&x,&y);
                printf("%lld
    ", query(1, 1, n, x, y));
            }
        }
        return 0;
    }
    Ac

    ---------------

    2的难度提升了,因为有两种不同的操作,加和乘。

    我们不难发现,应该先乘后加,不然会碰到一个除法。

    并且在乘的时候要给两个懒标记一块乘

    注意懒标记的初始化和取模

    ------------

    代码时间

    (线段树这东西太长了)

    #include<iostream>
    #include<cstdio>
    int n,m;
    long long mod = 571373;
    long long sum[400005],lazyadd[400005],lazymul[400005];
    int x,y,f;
    long long k;
    void pushdown(int x,int l,int r){
        if(lazymul[x]!=1){
            int mid=(l+r)>>1;
            lazyadd[x<<1]*=lazymul[x];lazyadd[x<<1]%=mod;//运用乘法分配律,把加发标记乘一下 
            lazyadd[x<<1|1]*=lazymul[x];lazyadd[x<<1|1]%=mod;
            lazymul[x<<1]*=lazymul[x];lazymul[x<<1]%=mod;//乘法标记乘起来就行了 
            lazymul[x<<1|1]*=lazymul[x];lazymul[x<<1|1]%=mod;
            sum[x<<1]*=lazymul[x];sum[x<<1]%=mod;//区间和肯定是直接乘的 
            sum[x<<1|1]*=lazymul[x];sum[x<<1|1]%=mod;
            lazymul[x]=1;
        }
        if (lazyadd[x] != 0){//然后处理加法 
            int mid=(l+r)>>1;
            lazyadd[x<<1]+=lazyadd[x];lazyadd[x<<1]%=mod;//和1没大有区别 
            sum[x<<1]+=lazyadd[x]*(mid-l+1);sum[x<<1]%=mod;
            lazyadd[x<<1|1]+=lazyadd[x];lazyadd[x<<1|1]%=mod;
            sum[x<<1|1]+=lazyadd[x]*(r-mid);sum[x<<1|1]%=mod;
            lazyadd[x]=0;
        }
        return ;
    }
    void pushup(int x){1 
        sum[x]=sum[x<<1]+sum[x<<1|1];
        sum[x]%=mod;//记得mod 
        return ;
    }
    void update1(int x,int l,int r,int L,int R,long long d){//节约空间牺牲时间的行为,而且要小心大小写的问题、
    //这个行为就是把这个点负责的左右区间放在函数里
    //如果存在数组里的话
    //用空间换时间 
    //简单的+ 
        if(L<=l&&r<=R){
            lazyadd[x]+=d;
            lazyadd[x]%=mod;
            sum[x]+=d*(r-l+1);
            sum[x]%=mod;
            return ;
        }
        int mid=(l+r)>>1;
        pushdown(x,l,r);
        if(L<=mid) update1(x<<1,l,mid,L,R,d);
        if(R>mid) update1(x<<1|1,mid+1,r,L,R,d);
        pushup(x);
    }
    void update2(int x,int l,int r,int L,int R,long long d){
        if(L<=l&&r<=R){
            lazyadd[x]*=d;//乘法分配律告诉我们,两个一起改 
            lazyadd[x]%=mod;
            lazymul[x]*=d;
            lazymul[x]%=mod;
            sum[x]*=d;//显然 
            sum[x]%=mod;
            return ;
        }
        int mid=(l+r)>>1;
        pushdown(x,l,r);
        if(L<=mid) update2(x<<1,l,mid,L,R,d);
        if(R>mid) update2(x<<1|1,mid+1,r,L,R,d);
        pushup(x);
    }
    long long query(int x,int l,int r,int L,int R){
        if(L<=l&&r<=R){
            return sum[x];
        }
        long long ans=0;
        int mid=(l+r)>>1;
        pushdown(x,l,r);
        if(L<=mid) ans+=query(x<<1,l,mid,L,R),ans%=mod;
        if(R>mid) ans+=query(x<<1|1,mid+1,r,L,R),ans%=mod;
        return ans;
    }
    int main(){
        scanf("%d%d%lld",&n,&m,&mod);
        for(int i=1;i<=400002;++i)
            lazymul[i]=1;
        for(int i=1;i<=n;++i){
            scanf("%d",&x);
            update1(1,1,n,i,i,x);
        }
        for(int i=1;i<=m;++i){
            scanf("%d",&f);
            if(f==1){
                scanf("%d%d%lld",&x,&y,&k);//嗯,这里的数字有点反 
                update2(1,1,n,x,y,k);
            }
            if(f==2){
                scanf("%d%d%lld",&x,&y,&k);
                update1(1,1,n,x,y,k);
            }
            if(f==3){
                scanf("%d%d",&x,&y);
                printf("%lld
    ",query(1,1,n,x,y));
            }
        }
        return 0;
    }
    Ac
  • 相关阅读:
    python
    python
    python
    python
    python
    python-接口自动化 token 的处理
    如何顺利度过试用期?
    印象深刻-bug汇总
    go 实现1000以内的数字,输入35 输出三十五
    jenkins 汉化
  • 原文地址:https://www.cnblogs.com/For-Miku/p/12346544.html
Copyright © 2011-2022 走看看