HYSBZ 1798(Ahoi2009) Seq 维护序列seq(区间更新+加法乘法混合操作)

1798: [Ahoi2009]Seq 维护序列seq

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

 
思路:线段树,注意两种操作不能简单的只往下传标记。每次传乘法标记时,要把加法标记同时乘上乘法标记,
   例如(A+B)*C,那么对应我们知道结果等同于A*C+B*C,那么我们在打lazy Tag的时候,如果对于当前区间有加法的部分,那么对应我们将这个加法部分乘上C。乘法部分的Lazy直接累乘上去即可。
 
代码:
#include <iostream>
#include <algorithm>
#include <string.h>
#include <cstdio>
#include <string>
#include <cmath>
#include <vector>
#include <stack>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
//#include <unordered_map>
#define Fbo friend bool operator < (node a, node b)
#define mem(a, b) memset(a, b, sizeof(a))
#define FOR(a, b, c) for (int a = b; a <= c; a++)
#define RFOR(a, b, c) for (int a = b; a >= c; a--)
#define off ios::sync_with_stdio(0)
#define sc(a) scanf("%lld",&a)
#define pr(a) printf("%lld\n",a);
#define SC(n,m) scanf("%lld%lld",&n,&m)
bool check1(int a) { return (a & (a - 1)) == 0 ? true : false; }

using namespace std;
typedef pair<int, int> pii;
typedef long long ll;
const int INF = 0x3f3f3f3f;//1e10
const int mod = 1e9 + 7;
const int Maxn = 2e5 + 9;
const int M = Maxn * 20;
const double pi = acos(-1.0);
const double eps = 1e-8;

ll a[Maxn],n,p,m,c,xx,x,y;

struct node {
    ll l, r;//区间[l,r]
    ll add;//区间加法
    ll sum;//区间和
    ll mul;//区间乘
}tree[Maxn * 4 + 5];//一定要开到4倍多的空间

void pushup(ll rt) { //向上更新
    tree[rt].sum = (tree[rt << 1].sum + tree[rt << 1 | 1].sum) % p;
}
void pushdown(ll rt) {//向下更新
    //if (tree[rt].add && tree[rt].mul == 0) { //若有标记,则讲标记向下移动一层

        tree[rt << 1].add = (tree[rt<<1].add * tree[rt].mul + tree[rt].add) % p;
        tree[rt << 1 | 1].add = (tree[rt << 1 | 1].add * tree[rt].mul + tree[rt].add) % p;

        tree[rt << 1].mul = (tree[rt << 1].mul * tree[rt].mul) % p;
        tree[rt << 1 | 1].mul = (tree[rt << 1 | 1].mul * tree[rt].mul) % p;

        tree[rt << 1].sum = (tree[rt << 1].sum * tree[rt].mul + (tree[rt << 1].r - tree[rt << 1].l + 1) * tree[rt].add) % p;
        tree[rt << 1 | 1].sum = (tree[rt << 1 | 1].sum * tree[rt].mul + (tree[rt << 1 | 1].r - tree[rt << 1 | 1].l + 1) * tree[rt].add) % p;

        tree[rt].add = 0;  //取消本层标记
        tree[rt].mul = 1;
   // }
}
void BuildTree(ll l, ll r, ll rt) {
    tree[rt].l = l;
    tree[rt].r = r;
    tree[rt].add = 0;
    tree[rt].mul = 1;
    //tree[rt].sum = r - l + 1; //更新结点rt的值
    if (l == r) {
        //此行根据题意看情况填什么————-
        tree[rt].sum = a[l];
        //————————————————
        return;
    }
    ll mid = (l + r) >> 1;
    BuildTree(l, mid, rt << 1); //递归左子树
    BuildTree(mid + 1, r, (rt << 1) + 1); //递归右子树
    pushup(rt);//向上更新
}
void updata(ll l, ll r, ll val, ll rt) { //root为结点 区间更新
     //   cout << l << " " << tree[rt].l << "----" << r << " " << tree[rt].r << endl; // 验证路径
    if (tree[rt].l >= l && tree[rt].r <= r) {
        if (xx == 1) {
            tree[rt].add = (tree[rt].add * val) % p;
            tree[rt].mul = (tree[rt].mul * val) % p;
            tree[rt].sum = (tree[rt].sum * val) % p;
            return;
        }
        else if (xx == 2) {
            tree[rt].add = (tree[rt].add + val) % p;
            tree[rt].sum = (tree[rt].sum + (ll)(tree[rt].r - tree[rt].l + 1) * val)%p;
            return;
        }
    }
    pushdown(rt);
    ll mid = (tree[rt].l + tree[rt].r) >> 1;
    if (l <= mid) {
        updata(l, r, val,rt << 1);
    }
    if (r > mid) {
        updata(l, r, val,rt << 1 | 1);
    }
    pushup(rt);//向上更新
}

ll querySum(ll l, ll r, ll rt) { //区间求和
    if (l <= tree[rt].l && r >= tree[rt].r) {
        return tree[rt].sum%p;
    }
    pushdown(rt);
    ll mid = (tree[rt].l + tree[rt].r) >> 1;
    ll ans = 0;
    if (l <= mid) {
        ans += querySum(l, r, rt << 1);
    }
    if (r > mid) {
        ans += querySum(l, r, rt << 1 | 1);
    }
    return ans%p;

}

int main() {
    SC(n, p);
    FOR(i, 1, n)sc(a[i]);
    BuildTree(1, n, 1);
    sc(m);
    while (m--) {
        sc(xx);
        if (xx == 1) {
            sc(x), sc(y), sc(c);
            updata(x, y, c, 1);
        }
        else if (xx == 2) {
            sc(x), sc(y), sc(c);
            updata(x, y, c, 1);
        }
        else if (xx == 3) {
            sc(x), sc(y);
            pr(querySum(x, y, 1));
        }
    }
    return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/AlexLINS/p/12745442.html
seq