zoukankan      html  css  js  c++  java
  • [AHOI2009]维护序列

    题目链接

    题目简介:我们要一个能同时支持加法与乘法的区间修改并查询区间求和的线段树。

    解题思路:这题目涉及到加法和乘法的前后顺序。这会直接导致答案的不同。于是有两种顺序:先加再乘or先乘再加。我们选择后者。因为前者的tag维护十分的不方便,每次加都对于后面的乘会有极大的影响。后者则不存在这些问题。维护的时候也按照这个顺序维护。所以直接上代码。

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #define cm long long mid=(l+r)>>1
    #define zc k<<1
    #define yc (k<<1)+1
    #define din l>=z&&r<=y
    #define dout r<z||l>y
    using namespace std;
    long long read(){
        char ch;
        long long res=0,f=1;
        ch=getchar();
        while(ch<'0'||ch>'9'){
            if(ch=='-')f=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            res=res*10+(ch-'0');
            ch=getchar();
        }
        return res*f;
    }
    const long long MAXN=1<<30;
    long long n,m,a[400005],xds_sum[400005],p,tag_x[400005],tag_add[400005];
    void pushdown(long long k,long long l,long long r){
        if(tag_x[k]==1&&tag_add[k]==0)return;
        cm;
        
        xds_sum[zc]=((xds_sum[zc]*tag_x[k])%p+(tag_add[k]*(mid-l+1))%p)%p;
        xds_sum[yc]=((xds_sum[yc]*tag_x[k])%p+(tag_add[k]*(r-mid))%p)%p;
        
        tag_x[zc]=(tag_x[zc]*tag_x[k])%p;
        tag_x[yc]=(tag_x[yc]*tag_x[k])%p;
        
        tag_add[zc]=(tag_add[zc]*tag_x[k]+tag_add[k])%p;
        tag_add[yc]=(tag_add[yc]*tag_x[k]+tag_add[k])%p;
        
        tag_x[k]=1;tag_add[k]=0;
    }
    void build(long long k,long long l,long long r){
        tag_x[k]=1;
        if(l==r){xds_sum[k]=a[l];return ;}
        cm;
        build(zc,l,mid);build(yc,mid+1,r);
        xds_sum[k]=(xds_sum[zc]+xds_sum[yc])%p;
    }
    long long query(long long k,long long l,long long r,long long z,long long y){
        if(din)return xds_sum[k];
        if(dout)return 0;
        cm;
        pushdown(k,l,r);
        return (query(zc,l,mid,z,y)+query(yc,mid+1,r,z,y))%p;
    }
    void change_add(long long k,long long l,long long r,long long z,long long y,long long v){
        if(dout)return;
        if(din){
            tag_add[k]=(tag_add[k]+v)%p;
            xds_sum[k]=(xds_sum[k]+v*(r-l+1))%p;
            return;
        }
        cm;
        pushdown(k,l,r);
        change_add(zc,l,mid,z,y,v);
        change_add(yc,mid+1,r,z,y,v);
        xds_sum[k]=(xds_sum[zc]+xds_sum[yc])%p;
    }
    void change_x(long long k,long long l,long long r,long long z,long long y,long long v){
        if(dout)return;
        if(din){
            tag_add[k]=(tag_add[k]*v)%p;
            tag_x[k]=(tag_x[k]*v)%p;
            xds_sum[k]=(xds_sum[k]*v)%p;
            return;
        }
        cm;
        pushdown(k,l,r);
        change_x(zc,l,mid,z,y,v);
        change_x(yc,mid+1,r,z,y,v);
        xds_sum[k]=(xds_sum[zc]+xds_sum[yc])%p;
    }
    int main(){
        n=read();p=read();
        for(long long i=1;i<=n;++i)a[i]=read();
        build(1,1,n);
        m=read();
        for(long long i=1;i<=m;++i){
            long long order,x,y,g;
            order=read();x=read();y=read();
            if(order==1){
                g=read();
                change_x(1,1,n,x,y,g);
            }
            else if(order==2){
                g=read();
                change_add(1,1,n,x,y,g);
            }
            else{
                cout<<query(1,1,n,x,y)<<endl;
            }
        }
        return 0;
    }
  • 相关阅读:
    PAT1134:Vertex Cover
    PAT1107:Sum of Number Segments
    PAT1009:Product of Polynomials
    力扣练习003---先序遍历构造二叉树(1008)
    力扣练习002---设计循环队列(622)
    力扣练习001---基本计算器(224)
    基础算法 --- 前缀和与差分
    数据结构 --- 二叉树
    基础算法 --- DFS(深度优先搜索)
    基础算法 --- BFS(广度优先搜索/宽度优先搜索)
  • 原文地址:https://www.cnblogs.com/clockwhite/p/11208739.html
Copyright © 2011-2022 走看看