洛谷 P3373 【模板】線段樹 2 題解

P3373 【模板】線段樹 2

題目描述

如題,已知一個數列,你須要進行下面三種操做:node

1.將某區間每個數乘上xios

2.將某區間每個數加上xui

3.求出某區間每個數的和spa

輸入格式

第一行包含三個整數N、M、P,分別表示該數列數字的個數、操做的總個數和模數。code

第二行包含N個用空格分隔的整數,其中第i個數字表示數列第i項的初始值。blog

接下來M行每行包含3或4個整數,表示一個操做,具體以下:get

操做1: 格式:1 x y k 含義:將區間[x,y]內每一個數乘上kio

操做2: 格式:2 x y k 含義:將區間[x,y]內每一個數加上k模板

操做3: 格式:3 x y 含義:輸出區間[x,y]內每一個數的和對P取模所得的結果class

輸出格式

輸出包含若干行整數,即爲全部操做3的結果。

輸入輸出樣例

輸入 #1

5 5 38
1 5 4 2 3
2 1 4 1
3 2 5
1 2 4 2
2 3 5 5
3 1 4

輸出 #1

17
2

說明/提示

時空限制:1000ms,128M

數據規模:

對於30%的數據:N<=8,M<=10

對於70%的數據:N<=1000,M<=10000

對於100%的數據:N<=100000,M<=100000

(數據已通過增強^_^)

樣例說明:

故輸出應爲1七、2(40 mod 38=2)

【思路】

線段樹
大部分的地方是和線段樹1這道題同樣的
我只在這裏說一下不一樣的地方

【取模】

在每一次有加法或者有乘法
涉及到運算的地方能模的都模一下就行了

【乘法和加法】

原來線段樹1模板裏面有一個lazy
那是由於有加法這種運算
如今有加法和乘法這兩種運算
那就開兩個相似lazy的東西儲存就行了

【lazy標記的修改】

在修改加法lazy標記的時候就正常修改就行了
可是修改乘法的時候就不行了
由於前面可能有加過的數
因此還要連帶着一塊兒修改一下加法的lazy標記
由於入過前面加過某個數
那如今就是
(a + b)
這個時候若是乘上一個數c
(a +b) * c = ac + bc
a乘了c,加法的lazy標記也乘了c因此要修改加法的標記

【完整代碼】

#include<iostream>
#include<cstdio>
#define int long long
#define lson (k << 1)
#define rson (k << 1 | 1)

using namespace std;
const int Max = 100005;
int read()
{
    int sum = 0,fg = 1;
    char c = getchar();
    while(c < '0' || c > '9')
    {
        if(c == '-')fg = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9')
    {
        sum = sum * 10 + c - '0';
        c = getchar(); 
    }
    return sum * fg;
}
int n,m,p;
int opl,opr,opx;
int ans;
struct node
{
    int l,r;
    int sum;
    int cheng,jia;
}a[Max << 2];

void build(int k,int l,int r)
{
    a[k].cheng = 1;
    a[k].jia = 0;
    a[k].l = l,a[k].r = r;
    if(l == r)
    {
        a[k].sum = read();
        a[k].sum %= p;
        return;
    }
    int mid = (l + r) >> 1;
    build(lson,l,mid);
    build(rson,mid + 1,r);
    a[k].sum = a[lson].sum + a[rson].sum;
    a[k].sum %= p;
}

void down(int k)
{
    if(a[k].jia != 0 || a[k].cheng != 1)
    {
        a[rson].cheng = (a[rson].cheng * a[k].cheng) % p;
        a[lson].cheng = (a[lson].cheng * a[k].cheng) % p;
        a[rson].jia = (a[rson].jia * a[k].cheng + a[k].jia) % p;
        a[lson].jia = (a[lson].jia * a[k].cheng + a[k].jia) % p;
        a[rson].sum = (a[rson].sum * a[k].cheng % p + a[k].jia * (a[rson].r - a[rson].l + 1)) % p;
        a[lson].sum = (a[lson].sum * a[k].cheng % p + a[k].jia * (a[lson].r - a[lson].l + 1)) % p;
        a[k].cheng = 1;
        a[k].jia = 0;
    }
}

void change1(int k)
{
    if(opl <= a[k].l && opr >= a[k].r)
    {
        a[k].cheng = (a[k].cheng * opx) % p;
        a[k].jia = (a[k].jia * opx) % p;
        a[k].sum = (a[k].sum * opx) % p;
        return;
    }
    down(k);
    int mid = (a[k].l + a[k].r) >> 1;
    if(opl <= mid)change1(lson);
    if(opr > mid)change1(rson);
    a[k].sum = (a[lson].sum + a[rson].sum) % p;
}

void change2(int k)
{
    if(opl <= a[k].l && opr >= a[k].r)
    {
        a[k].jia = (a[k].jia + opx) % p;
        a[k].sum = (a[k].sum + (a[k].r - a[k].l + 1) * opx % p) % p;
        return;
    }
    down(k);
    int mid = (a[k].l + a[k].r) >> 1;
    if(opl <= mid)change2(lson);
    if(opr > mid)change2(rson);
    a[k].sum = (a[lson].sum + a[rson].sum) % p;
} 

void query(int k)
{
    if(opl <= a[k].l && opr >= a[k].r)
    {
        ans += a[k].sum;
        ans %= p;
        return;
    }
    down(k);
    int mid = (a[k].l + a[k].r) >> 1;
    if(opl <= mid)query(lson);
    if(opr > mid)query(rson);
}

signed main()
{
    n = read(),m = read(),p = read();
    build(1,1,n);
    for(register int i = 1;i <= m;++ i)
    {
        int qwq = read();
        if(qwq == 1)
        {
            opl = read(),opr = read(),opx = read();
            change1(1);
        }
        else
        if(qwq == 2)
        {
            opl = read(),opr = read(),opx = read();
            change2(1);
        }
        else
        {
            opl = read(),opr = read();
            ans = 0;
            query(1);
            cout << ans % p << endl; 
        }
    }
    return 0;
}
相關文章
相關標籤/搜索