「线段树」[AHOI2009]维护序列

Posted nicoppa

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「线段树」[AHOI2009]维护序列相关的知识,希望对你有一定的参考价值。

双倍经验,还是蓝题,岂不美哉

题目描述

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

输入格式

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

输出格式

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

输入输出样例

输入

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

输出

2
35
8

说明/提示

【样例说明】

初始时数列为(1,2,3,4,5,6,7)。

经过第1次操作后,数列为(1,10,15,20,25,6,7)。

对第2次操作,和为10+15+20=45,模43的结果是2。

经过第3次操作后,数列为(1,10,24,29,34,15,16

对第4次操作,和为1+10+24=35,模43的结果是35。

对第5次操作,和为29+34+15+16=94,模43的结果是8。

测试数据规模如下表所示

数据编号 1 2 3 4 5 6 7 8 9 10

N= 10 1000 1000 10000 60000 70000 80000 90000 100000 100000

M= 10 1000 1000 10000 60000 70000 80000 90000 100000 100000

Source: Ahoi 2009

题目题解

还是三个操作,线段树基本题

//#define fre yes

#include <cstdio>
#define int long long

const int N = 100005;
struct Node 
    int l, r;
    long long sum, addv, mul;
 tree[N << 2];
int MOD;

long long ans;

void build(int k, int l, int r) 
    tree[k].l = l; tree[k].r = r; tree[k].addv = 0; tree[k].mul = 1;
    if(l == r) 
        scanf("%lld", &tree[k].sum);
        tree[k].sum %= MOD;
        return ;
    
    
    int mid = (l + r) >> 1;
    build(k * 2, l, mid);
    build(k * 2 + 1, mid + 1, r);
    tree[k].sum = (tree[k * 2].sum + tree[k * 2 + 1].sum) % MOD;


void update(int k) 
    tree[k * 2].addv = (tree[k].mul * tree[k * 2].addv + tree[k].addv) % MOD;
    tree[k * 2 + 1].addv = (tree[k].mul * tree[k * 2 + 1].addv + tree[k].addv) % MOD;
    tree[k * 2].mul = (tree[k].mul * tree[k * 2].mul) % MOD;
    tree[k * 2 + 1].mul = (tree[k].mul * tree[k * 2 + 1].mul) % MOD;
    tree[k * 2].sum = (tree[k * 2].sum * tree[k].mul + (tree[k * 2].r - tree[k * 2].l + 1) * tree[k].addv) % MOD;
    tree[k * 2 + 1].sum = (tree[k * 2 + 1].sum * tree[k].mul + (tree[k * 2 + 1].r - tree[k * 2 + 1].l + 1) * tree[k].addv) % MOD;
    tree[k].addv = 0;
    tree[k].mul = 1;


void mul_interval(int k, int l, int r, int x) 
    if(tree[k].l >= l && tree[k].r <= r) 
        tree[k].sum = (tree[k].sum * x) % MOD;
        tree[k].addv = (tree[k].addv * x) % MOD;
        tree[k].mul = (tree[k].mul * x) % MOD;
        return ;
    
    
    if(tree[k].addv || tree[k].mul != 1) update(k);
    int mid = (tree[k].l + tree[k].r) >> 1;
    if(mid >= l) mul_interval(k * 2, l, r, x);
    if(mid < r) mul_interval(k * 2 + 1, l, r, x);
    tree[k].sum = (tree[k * 2].sum + tree[k * 2 + 1].sum) % MOD;


void add_interval(int k, int l, int r, int x) 
    if(tree[k].l >= l && tree[k].r <= r) 
        tree[k].sum = (tree[k].sum + (tree[k].r - tree[k].l + 1) * x) % MOD;
        tree[k].addv = (tree[k].addv + x) % MOD;
        return ;
    
    
    if(tree[k].addv || tree[k].mul != 1) update(k);
    int mid = (tree[k].l + tree[k].r) >> 1;
    if(mid >= l) add_interval(k * 2, l, r, x);
    if(mid < r) add_interval(k * 2 + 1, l, r, x);
    tree[k].sum = (tree[k * 2].sum + tree[k * 2 + 1].sum) % MOD;


void query(int k, int l, int r) 
    if(tree[k].l >= l && tree[k].r <= r) 
        ans = (ans + tree[k].sum) % MOD;
        return ;
    
    
    if(tree[k].addv || tree[k].mul != 1) update(k);
    int mid = (tree[k].l + tree[k].r) >> 1;
    if(mid >= l) query(k * 2, l, r);
    if(mid < r) query(k * 2 + 1, l, r);


signed main() 
    static int n, m;
    scanf("%lld %lld", &n, &MOD);
    build(1, 1, n);
    scanf("%lld", &m);
    for (int i = 1; i <= m; i++) 
        int k;
        scanf("%lld", &k);
        if(k == 1) 
            int l, r, x;
            scanf("%lld %lld %lld", &l, &r, &x);
            mul_interval(1, l, r, x);
        
        if(k == 2) 
            int l, r, x;
            scanf("%lld %lld %lld", &l, &r, &x);
            add_interval(1, l, r, x);
        
        if(k == 3) 
            int l, r; ans = 0;
            scanf("%lld %lld", &l, &r);
            query(1, l, r);
            printf("%lld\n", ans % MOD);
        
     return 0;

以上是关于「线段树」[AHOI2009]维护序列的主要内容,如果未能解决你的问题,请参考以下文章

P2023 [AHOI2009]维护序列 题解(线段树

BZOJ_1798_[AHOI2009]维护序列_线段树

bzoj1798: [Ahoi2009]Seq 维护序列seq(线段树)

BZOJ1798: [Ahoi2009]Seq 维护序列seq[线段树]

P2023 [AHOI2009]维护序列 (线段树区间修改查询)

bzoj1798: [Ahoi2009]Seq 维护序列seq 线段树