洛谷P2023 [AHOI2009]维护序列(线段树)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhanghaoxian1/article/details/82049024

[AHOI2009]维护序列

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

输入输出格式
输入格式:
第一行两个整数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)。 同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。

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

输入输出样例
输入样例#1:
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
输出样例#1:
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。

分析:对于一次乘法操作,把乘法标记和加法标记都乘这个数即可,其他的正常操作。

代码

#include <cstdio>
#define N 500000
#define ll long long
using namespace std;

struct tree
{
    int l, r;
    ll add, mul, sum;
}tr[N];
ll a[N],mo,ans;
int n,m;

void build(int p)
{
    tr[p].mul = 1;
    if (tr[p].l == tr[p].r)
    {
        tr[p].sum = a[tr[p].l];
        return;
    }
    int mid = (tr[p].l + tr[p].r) / 2;
    tr[p * 2].l = tr[p].l;
    tr[p * 2].r = mid;
    tr[p * 2 + 1].l =mid + 1;
    tr[p * 2 + 1].r = tr[p].r;
    build(p * 2);
    build(p * 2 + 1);
    tr[p].sum = (tr[p * 2].sum + tr[p * 2 + 1].sum) % mo;
}

void down(int p)
{
    tr[p * 2].add = ((tr[p].mul * tr[p * 2].add) % mo + tr[p].add) % mo;
    tr[p * 2].mul = tr[p * 2].mul * tr[p].mul % mo;
    tr[p * 2].sum = ((tr[p].mul * tr[p * 2].sum % mo) + tr[p].add * (tr[p * 2].r - tr[p * 2].l + 1) % mo) % mo;
    tr[p * 2 + 1].add = ((tr[p].mul * tr[p * 2 + 1].add) % mo + tr[p].add) % mo;
    tr[p * 2 + 1].mul = tr[p * 2 + 1].mul * tr[p].mul % mo;
    tr[p * 2 + 1].sum = ((tr[p].mul * tr[p * 2 + 1].sum % mo) + tr[p].add * (tr[p * 2 + 1].r - tr[p * 2 + 1].l + 1) % mo) % mo;
    tr[p].mul = 1;
    tr[p].add = 0;
}

void find(int p, int x, int y)
{
    if (tr[p].l == x && tr[p].r == y)
    {
        ans = (ans + tr[p].sum) % mo;
        return;
    }
    down(p);
    int mid = (tr[p].l + tr[p].r) / 2;
    if (y <= mid) find(p * 2, x, y);
        else if (x > mid) find(p * 2 + 1, x, y);
            else find(p * 2, x, mid), find(p * 2 + 1, mid + 1, y);
}

void change(int p, int x, int y, ll val, int op)
{
    if (tr[p].l == x && tr[p].r == y)
    {
        if (op == 1) 
        {
            tr[p].mul = tr[p].mul * val % mo;
            tr[p].add = tr[p].add * val % mo;
            tr[p].sum = val * tr[p].sum % mo;
        }
        else tr[p].add = (tr[p].add + val) % mo, tr[p].sum = (tr[p].sum + val * (tr[p].r - tr[p].l + 1) % mo) % mo;
        return;
    }
    down(p);
    int mid = (tr[p].l + tr[p].r) / 2;
    if (y <= mid) change(p * 2, x, y, val, op);
        else if (x > mid) change(p * 2 + 1, x, y, val, op);
            else change(p * 2, x, mid, val, op), change(p * 2 + 1, mid + 1, y, val, op);
    tr[p].sum = (tr[p * 2].sum + tr[p * 2 + 1].sum) % mo;
}

int main()
{
    scanf("%d%lld", &n, &mo);
    for (int i = 1; i <= n; i++)
        scanf("%lld", &a[i]);
    tr[1].l = 1;
    tr[1].r = n;
    build(1);
    scanf("%d", &m);
    for (int i = 1; i <= m; i++)
    {
        int op, x, y;
        scanf("%d%d%d", &op, &x, &y);
        if (op == 3)
        {
            ans = 0;
            find(1, x, y);
            printf("%lld\n", ans);
        }
        else 
        {
            ll z = 0;
            scanf("%lld", &z);
            change(1, x, y, z, op);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/zhanghaoxian1/article/details/82049024
今日推荐