BZOJ1798 维护序列seq

1798: [Ahoi2009]Seq 维护序列seq

Time Limit: 30 Sec  Memory Limit: 64 MB
Submit: 8058  Solved: 2964
[Submit][Status][Discuss]

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
 
从中午写题开始一直写到晚上转钟,中间写了无数次bug和被自己手抖写错了一个地方
找bug真的是难受,以后这样就直接重新写吧
题意:线段树的查询、区间修改、sum和的操作
题解:从某大佬的专题学习了线段树在结构体里面的写法,在结构体里面创建树的话,就可以直接调用和查询
   板子题了,用sum数组来存这颗树,每次插入操作对树上的每一段区间/节点都进行一次update
代码如下:
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 8e5+5;
long long mod;
long long n,m;
struct segtree{
    #define lc(x) (x*2)
    #define rc(x) (x*2+1)
    long long l[maxn],r[maxn];
    long long sumi[maxn],mul[maxn],add[maxn];
    void build(int x,int L,int R){
        //数组从1开始
        l[x]=L;
        r[x]=R;
        add[x]=0;
        mul[x]=1;
        if(L==R){
            //区间节点
            cin>>sumi[x];
            return;
        }
        int mid=(L+R)/2;
        build(lc(x),L,mid);
        build(rc(x),mid+1,R);
        update(x);
    }
    void update(int x){
        sumi[x]=(sumi[lc(x)]+sumi[rc(x)])%mod;
    }
    void push(int x){
        mul[lc(x)]=(mul[lc(x)]*mul[x])%mod;
        mul[rc(x)]=(mul[rc(x)]*mul[x])%mod;
        add[lc(x)]=(add[lc(x)]*mul[x]+add[x])%mod;
        add[rc(x)]=(add[rc(x)]*mul[x]+add[x])%mod;
        sumi[lc(x)]=(sumi[lc(x)]*mul[x]+
                        add[x]*(r[lc(x)]-l[lc(x)]+1))%mod;
        sumi[rc(x)]=(sumi[rc(x)]*mul[x]+
                        add[x]*(r[rc(x)]-l[rc(x)]+1))%mod;
        add[x]=0;
        mul[x]=1;
    }
    void ADD(int x,int L,int R,long long v){
        push(x);
        if(R<l[x]||L>r[x]) return;   //查询区间不在范围内
        if(L<=l[x]&&r[x]<=R){
            sumi[x]=(sumi[x]+v*(r[x]-l[x]+1))%mod;
            add[x]=(add[x]+v)%mod;
            return;
        }
        ADD(lc(x),L,R,v);
        ADD(rc(x),L,R,v);
        update(x);
    }
    void MUL(int x,int L,int R,long long v){
        push(x);
        if(R<l[x]||L>r[x]) return;
        if(L<=l[x]&&r[x]<=R){
            sumi[x]=(sumi[x]*v)%mod;
            add[x]=(add[x]*v)%mod;
            mul[x]=(mul[x]*v)%mod;
            return;
        }
        MUL(lc(x),L,R,v);
        MUL(rc(x),L,R,v);
        update(x);
    }
    long long Qsum(int x,int L,int R){
            push(x);
            if(l[x]>R||r[x]<L) return 0;
            if(L<=l[x]&&r[x]<=R) return sumi[x];
            return (Qsum(lc(x),L,R)+Qsum(rc(x),L,R))%mod;
    }
}seg;

int main(){
    cin>>n>>mod;
    seg.build(1,1,n);
    cin>>m;
    for(long long i= 1,op,l,r;i<=m;i++){
        cin>>op>>l>>r;
        if(op==3) {
            cout<<seg.Qsum(1,l,r)<<endl;
        }
        else{
            long long v;
            cin>>v;
            if(op==1) seg.MUL(1,l,r,v);
            else seg.ADD(1,l,r,v);
        }
    }
    return 0;
}
View Code

 

每一个不曾刷题的日子 都是对生命的辜负 从弱小到强大,需要一段时间的沉淀,就是现在了 ~buerdepepeqi
posted @ 2018-07-25 00:36  buerdepepeqi  阅读(114)  评论(0编辑  收藏  举报