1. 程式人生 > >[洛谷P2023] [AHOI2009]維護序列

[洛谷P2023] [AHOI2009]維護序列

con out CP 雙引號 表示 支持 rand() 為什麽 tag

洛谷題目鏈接:[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。

測試數據規模如下表所示

數據編號 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

一句話題意: 寫一中數據結構支持區間加法/乘法,以及區間求和.

題解: 維護方式多種多樣,這裏使用的是無旋treap.當然這題主要是來練習標記下放的.可以維護一個乘法標記,一個加法標記,在下放的時候要先下放乘法標記. 為什麽呢?假設先有一個加法標記打在這個區間上,那麽直接將加法標記也乘上這個修改的值就可以了.假設先有乘法標記,那麽也會先將乘法標記下放,所以是沒有問題的.

還有就是修改的時候下放到左右兒子的標記的值都只需要用這個點的標記值來修改,比如說乘法:

應該是

(t[ls].sum *= t[x].mul) %= mod; (t[rs].sum *= t[x].mul) %= mod;

而不是

(t[ls].sum *= t[ls].mul) %= mod; (t[rs].sum *= t[ls].mul) %= mod;

因為之前如果有標記打在這個區間上,那麽它就已經對這個區間的sum,val等信息都已經修改過了.

然後就是每個地方取mod都處理好,開個long long就可以了.

#include<bits/stdc++.h>
#define debug out(root), printf("\n")
using namespace std;
typedef long long lol;
const int N=100000+5;

lol n, m, mod, a[N], root, cnt = 0, r1, r2, r3;

struct treap{
    lol ch[2], rd, size, val, sum, tag, mul;
}t[N];

inline lol gi(){
    lol ans = 0, f = 1; char i = getchar();
    while(i<'0'||i>'9'){if(i=='-')f=-1;i=getchar();}
    while(i>='0'&&i<='9'){ans=ans*10+i-'0';i=getchar();}
    return ans * f;
}

inline lol newnode(lol val){
    t[++cnt].rd = rand(); t[cnt].size = t[cnt].mul = 1;
    t[cnt].val = t[cnt].sum = val; t[cnt].tag = 0;
    return cnt;
}

inline void up(lol x){
    lol ls = t[x].ch[0], rs = t[x].ch[1];
    t[x].sum = (t[ls].sum+t[x].val+t[rs].sum)%mod;
    t[x].size = t[ls].size+t[rs].size+1;
}

inline void pushdown(lol x){
    lol ls = t[x].ch[0], rs = t[x].ch[1];
    if(t[x].mul != 1){
        (t[ls].mul *= t[x].mul) %= mod; (t[rs].mul *= t[x].mul) %= mod;
        (t[ls].tag *= t[x].mul) %= mod; (t[rs].tag *= t[x].mul) %= mod;
        (t[ls].val *= t[x].mul) %= mod; (t[rs].val *= t[x].mul) %= mod;
        (t[ls].sum *= t[x].mul) %= mod; (t[rs].sum *= t[x].mul) %= mod;
        t[x].mul = 1;
    }
    if(t[x].tag){
        (t[ls].tag += t[x].tag) %= mod; (t[rs].tag += t[x].tag) %= mod;
        (t[ls].val += t[x].tag) %= mod; (t[rs].val += t[x].tag) %= mod;
        (t[ls].sum += (t[x].tag*t[ls].size)%mod) %= mod;
    (t[rs].sum += (t[x].tag*t[rs].size)%mod) %= mod;
        t[x].tag = 0;
    }
}

inline void split(lol x, lol k, lol &a, lol &b){
    if(x == 0){a = b = 0; return;} pushdown(x);
    if(k <= t[t[x].ch[0]].size) b = x, split(t[x].ch[0], k, a, t[x].ch[0]);
    else a = x, split(t[x].ch[1], k-t[t[x].ch[0]].size-1, t[x].ch[1], b); up(x);
}

inline lol merge(lol x, lol y){
    if(x == 0 || y == 0) return x+y;
    pushdown(x), pushdown(y);
    if(t[x].rd < t[y].rd){
        t[x].ch[1] = merge(t[x].ch[1], y);
        up(x); return x;
    } else {
        t[y].ch[0] = merge(x, t[y].ch[0]);
        up(y); return y;
    }
}

inline void insert(lol val, lol pos){
    split(root, pos, r1, r2);
    root = merge(r1, merge(newnode(val), r2));
}

inline lol query(lol x, lol y){
    lol res;
    split(root, y, r2, r3); split(r2, x-1, r1, r2);
    res = t[r2].sum; root = merge(r1, merge(r2, r3));
    return res;
}

inline void update(lol x, lol y, lol z){
    z %= mod; split(root, y, r2, r3); split(r2, x-1, r1, r2);
    (t[r2].tag += z) %= mod; (t[r2].val += z) %= mod;
    (t[r2].sum += z*t[r2].size) %= mod;
    pushdown(r2); root = merge(r1, merge(r2, r3));
}

inline void multiply(lol x, lol y, lol z){
    z %= mod; split(root, y, r2, r3); split(r2, x-1, r1, r2);
    (t[r2].mul *= z) %= mod; (t[r2].tag *= z) %= mod;
    (t[r2].val *= z) %= mod; (t[r2].sum *= z) %= mod;
    pushdown(r2); root = merge(r1, merge(r2, r3));
}

int main(){
    lol opt, x, y, z; n = gi(), mod = gi();
    for(lol i=1; i<=n; i++) x = gi(), insert(x%mod, i-1);
    m = gi();
    for(lol i=1; i<=m; i++){
        opt = gi(), x = gi(), y = gi();
        if(opt == 1) z = gi(), multiply(x, y, z);
        if(opt == 2) z = gi(), update(x, y, z);
        if(opt == 3) printf("%lld\n", query(x, y));
    }
    return 0;
}

[洛谷P2023] [AHOI2009]維護序列