bzoj1798 [Ahoi2009]Seq 维护序列seq

1798: [Ahoi2009]Seq 维护序列seq

Time Limit: 30 Sec  Memory Limit: 64 MB
Submit: 5375  Solved: 1899
[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

HINT

【样例说明】

初始时数列为(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

Day1

分析:很显然,本题要用线段树做,但是怎么用线段树倒是个问题.可以想到先建树,每次修改一个区间的值把这个区间所包含的区间的值给修改了即可,但是这样太花时间了,有没有省时间的方法呢?一个著名的思想lazy-tag就出现了,想要详细了解lazy-tag,可以取看看这篇博客:传送门.

       简单来说,如果要修改一个区间的值,如果这个区间刚好被完全包含了就直接返回,打上标记(要改成多少),那么下次要用子节点的时候将标记下传即可,显然,对于本题要打两个tag,那么sum[o] = sum[o] * mul[o] + add[o],sum为和,mul为乘的数,add为加的数,那么如果我们乘一个数c,sum[o] = sum[o] * mul[o] * c + add[o] * c,将mul[o] * c和add[o] * c看作两个整体,那么可以发现如果乘一个数c的话,add数组要*c,mul数组也要*c,同理,如果加一个数c,那么只需要add数组+c即可,因为在下传标记的时候既有加,又有减(可能为0),所以add和mul数组的计算一定要将这两种情况都计算到.

       如果在线段树上几个区间操作的性质相同的,先把要求的数用操作需要的量给表示出来,然后对于每一种操作看看需要维护的标记的变化,最后合并一下即可.

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

#define le l,mid,o * 2
#define re mid + 1,r,o * 2 + 1

using namespace std;

const long long maxn = 1000010;

long long n, p,a[maxn],add[maxn],mul[maxn],sum[maxn],m;

void build(int l, int r, int o)
{
    mul[o] = 1;
    add[o] = 0;
    if (l == r)
    {
        sum[o] = a[l];
        return;
    }
    int mid = (l + r) >> 1;
    build(le);
    build(re);
    sum[o] = (sum[o * 2] + sum[o * 2 + 1]) % p;
}

void pushdown(int o, int k)
{
    sum[o * 2] = (sum[o * 2] * mul[o] + add[o] * (k - (k >> 1))) % p;
    sum[o * 2 + 1] = (sum[o * 2 + 1] * mul[o] + add[o] * (k >> 1)) % p;
    mul[o * 2] = mul[o * 2] * mul[o] % p;
    mul[o * 2 + 1] = mul[o * 2 + 1] * mul[o] % p;
    add[o * 2] = (add[o * 2] * mul[o] + add[o]) % p;
    add[o * 2 + 1] = (add[o * 2 + 1] * mul[o] + add[o]) % p;
    mul[o] = 1;
    add[o] = 0;
}

void jia(int l, int r, int o, int x, int y, int v)
{
    if (x <= l && r <= y)
    {
        add[o] = (add[o] + v) % p;
        sum[o] = (sum[o] + v * (r - l + 1)) % p;
        return;
    }
    pushdown(o, r - l + 1);
    int mid = (l + r) >> 1;
    if (x <= mid)
        jia(le, x, y, v);
    if (y > mid)
        jia(re, x, y, v);
    sum[o] = (sum[o * 2] + sum[o * 2 + 1]) % p;
}

void cheng(int l, int r, int o, int x, int y, int v)
{
    if (x <= l && r <= y)
    {
        add[o] = (add[o] * v) % p;
        mul[o] = (mul[o] * v) % p;
        sum[o] = (sum[o] * v) % p;
        return;
    }
    pushdown(o, r - l + 1);
    int mid = (l + r) >> 1;
    if (x <= mid)
        cheng(le, x, y, v);
    if (y > mid)
        cheng(re, x, y, v);
    sum[o] = (sum[o * 2] + sum[o * 2 + 1]) % p;
}

long long query(int l, int r, int o, int x, int y)
{
    if (x <= l && r <= y)
        return sum[o] % p;
    int mid = (l + r) >> 1;
    pushdown(o, r - l + 1);
    long long temp = 0;
    if (x <= mid)
        temp = (temp + query(le, x, y)) % p;
    if (y > mid)
        temp = (temp + query(re, x, y)) % p;
    sum[o] = (sum[o * 2] + sum[o * 2 + 1]) % p;
    return temp % p;
}

int main()
{
    scanf("%lld%lld", &n, &p);
    for (int i = 1; i <= n; i++)
        scanf("%lld", &a[i]);
    build(1, n, 1);
    scanf("%lld", &m);
    while (m--)
    {
        int op, t, g,c;
        scanf("%d%d%d", &op, &t, &g);
        if (op == 1)
        {
            scanf("%d", &c);
            cheng(1, n, 1, t, g, c);
        }
        if (op == 2)
        {
            scanf("%d", &c);
            jia(1, n, 1, t, g, c);
        }
        if (op == 3)
            printf("%lld\n", query(1, n, 1, t, g) % p);
    }

    return 0;
}

 

posted @ 2016-09-10 17:23  zbtrs  阅读(849)  评论(0编辑  收藏  举报