zoukankan      html  css  js  c++  java
  • 【线段树】Bzoj1798 [AHOI2009] 维护序列

    Description

    老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。 有长为N的数列,不妨设为a1,a2,…,aN 。有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模P的值。

    Input

    第一行两个整数N和P(1≤P≤1000000000)。第二行含有N个非负整数,从左到右依次为a1,a2,…,aN, (0≤ai≤1000000000,1≤i≤N)。第三行有一个整数M,表示操作总数。从第四行开始每行描述一个操作,输入的操作有以下三种形式: 操作1:“1 t g c”(不含双引号)。表示把所有满足t≤i≤g的ai改为ai×c (1≤t≤g≤N,0≤c≤1000000000)。 操作2:“2 t g c”(不含双引号)。表示把所有满足t≤i≤g的ai改为ai+c (1≤t≤g≤N,0≤c≤1000000000)。 操作3:“3 t g”(不含双引号)。询问所有满足t≤i≤g的ai的和模P的值 (1≤t≤g≤N)。 同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。

    Output

    对每个操作3,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。

    Sample Input

    7 43
    1 2 3 4 5 6 7
    5
    1 2 5 5
    3 2 4
    2 3 7 9
    3 1 3
    3 4 7

    Sample Output

    2
    35
    8
     

    题解

    三个数组sum, mul, add,具体操作看代码

    要注意前面操作对当前的影响,及时pushback,统计祖先add&mul也要想清

    以后做这种题目都要想清定义,每一步的影响,不然就都乱了

    以后要自己想清造小数据过了后再去搞大数据拍,自己造的数据密度大很多的,而且先要保证正确性才行

    代码

    非常不愉快,打完后找标程对拍,大数据不一样,调了好久,结果是标程有问题QwQ

    以后全部用ll保平安啦

    #include<cstdio>
    #define ll long long
    const int maxn=4e5+5;
    
    ll sumv[maxn],mulv[maxn],addv[maxn];
    ll N,M,mod,p,q,w,x;
    
    void pushup(ll o,ll l,ll r){
        sumv[o]=0;
        if(l<r) sumv[o]=sumv[o*2]+sumv[o*2+1];
        sumv[o]*=mulv[o],sumv[o]%=mod;
        sumv[o]+=(r-l+1)*addv[o],sumv[o]%=mod;
    }
    
    void pushdown(ll o,ll l,ll r){
        ll Mul=mulv[o],Add=addv[o],lc=o*2,rc=o*2+1,mid=(l+r)>>1;
        sumv[lc]=(sumv[lc]*Mul+(mid-l+1)*Add)%mod;
        sumv[rc]=(sumv[rc]*Mul+(r-mid)*Add)%mod;
        mulv[lc]=(mulv[lc]*Mul)%mod;
        mulv[rc]=(mulv[rc]*Mul)%mod;
        addv[lc]=(addv[lc]*Mul+Add)%mod;
        addv[rc]=(addv[rc]*Mul+Add)%mod;
        mulv[o]=1;addv[o]=0;
    }
    
    void add(ll o,ll l,ll r){
        if(p<=l&&q>=r) addv[o]+=w,addv[o]%=mod;
        else{
            pushdown(o,l,r);
            int mid=(l+r)/2;
            if(p<=mid) add(o*2,l,mid);
            if(q>mid) add(o*2+1,mid+1,r);
        }
        pushup(o,l,r);
    }
    
    void mul(ll o,ll l,ll r){
        if(p<=l&&q>=r){
            mulv[o]*=w,mulv[o]%=mod;
            addv[o]*=w,addv[o]%=mod;
        }
        else{
            pushdown(o,l,r);
            int mid=(l+r)/2;
            if(p<=mid) mul(o*2,l,mid);
            if(q>mid) mul(o*2+1,mid+1,r);
        }
        pushup(o,l,r);
    }
    
    ll ret;
    void sum(ll o,ll l,ll r,ll Add,ll Mul){
        if(p<=l&&q>=r){
            ret+=Mul*sumv[o]+Add*(r-l+1);
            ret%=mod;
        }
        else{
            int mid=(l+r)/2;
            if(p<=mid) sum(o*2,l,mid,(Add+Mul*addv[o])%mod,Mul*mulv[o]%mod);
            if(q>mid) sum(o*2+1,mid+1,r,(Add+Mul*addv[o])%mod,Mul*mulv[o]%mod);
        }
    }
    
    int main(){
        scanf("%lld%lld",&N,&mod);
        for(int i=1;i<=3*N;i++) mulv[i]=1;
        
        for(int i=1;i<=N;i++){
            scanf("%lld",&w);
            p=q=i;
            add(1,1,N);
        }
        
        scanf("%lld",&M);
        for(int i=1;i<=M;i++){
            scanf("%lld",&x);
            if(x==1){
                scanf("%lld%lld%lld",&p,&q,&w);
                mul(1,1,N);
            }
            else if(x==2){
                scanf("%lld%lld%lld",&p,&q,&w);
                add(1,1,N);
            }
            else{
                scanf("%lld%lld",&p,&q);
                ret=0;
                sum(1,1,N,0,1);
                printf("%lld
    ",ret);
                continue;
            }
        }
        
        return 0;
    }
  • 相关阅读:
    操作系统学习(一)、80x86保护模式内存管理
    Linux命令(十三) 建立目录 mkdir 删除目录 rmdir
    Linux命令(十二) 分割文件 split 合并文件 join
    Linux命令(十一) 显示文件类型 file
    linux下环境变量PS1设置
    Jenkins email-ext邮件通知模板
    building system busy, pls wait !!
    SCP 命令
    NDK Build 用法(NDK Build)
    android下m、mm、mmm编译命令的使用
  • 原文地址:https://www.cnblogs.com/xkui/p/4539833.html
Copyright © 2011-2022 走看看