[BZOJ1798][Ahoi2009]Seq 维护序列seq
[BZOJ1798][Ahoi2009]Seq 维护序列seq
试题描述
老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。 有长为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,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。
输入示例
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
输出示例
2 35 8
数据规模及约定
N ≤ 100000, M ≤ 100000
题解
线段树,打标记恶心一些。因为有乘法分配律,所以在乘法懒标记下传时把加法的懒标记也乘一下,加法懒标记还是该怎么打怎么打。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std;
const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *Tail;
inline char Getchar() {
if(Head == Tail) {
int l = fread(buffer, 1, BufferSize, stdin);
Tail = (Head = buffer) + l;
}
return *Head++;
}
int read() {
int x = 0, f = 1; char c = Getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
return x * f;
}
#define maxn 100010
#define LL long long
int n, val[maxn];
LL MOD, sumv[maxn<<2], addv[maxn<<2], timv[maxn<<2];
void maintain(int L, int R, int o) {
int M = L + R >> 1, lc = o << 1, rc = lc | 1;
if(L == R) return ;
sumv[o] = ((sumv[lc] * timv[lc] % MOD + addv[lc] * (LL)(M - L + 1) % MOD) % MOD + (sumv[rc] * timv[rc] % MOD + addv[rc] * (LL)(R - M) % MOD) % MOD) % MOD;
return ;
}
void build(int L, int R, int o) {
timv[o] = 1;
if(L == R) sumv[o] = val[L];
else {
int M = L + R >> 1, lc = o << 1, rc = lc | 1;
build(L, M, lc); build(M+1, R, rc);
maintain(L, R, o);
}
return ;
}
void pushdown(int L, int R, int o) {
int M = L + R >> 1, lc = o << 1, rc = lc | 1;
LL len = (LL)(R - L + 1);
if(timv[o] != 1) {
(sumv[o] *= timv[o]) %= MOD;
if(L != R) {
(timv[lc] *= timv[o]) %= MOD; (addv[lc] *= timv[o]) %= MOD;
(timv[rc] *= timv[o]) %= MOD; (addv[rc] *= timv[o]) %= MOD;
}
timv[o] = 1;
}
if(addv[o]) {
sumv[o] += (addv[o] * len % MOD); if(sumv[o] >= MOD) sumv[o] -= MOD;
if(L != R) {
addv[lc] += addv[o]; if(addv[lc] >= MOD) addv[lc] -= MOD;
addv[rc] += addv[o]; if(addv[rc] >= MOD) addv[rc] -= MOD;
}
addv[o] = 0;
}
return ;
}
void update1(int L, int R, int o, int ql, int qr, LL v) {
pushdown(L, R, o);
if(ql <= L && R <= qr) (timv[o] *= v) %= MOD, (addv[o] *= v) %= MOD;
else {
int M = L + R >> 1, lc = o << 1, rc = lc | 1;
if(ql <= M) update1(L, M, lc, ql, qr, v);
if(qr > M) update1(M+1, R, rc, ql, qr, v);
}
maintain(L, R, o);
return ;
}
void update2(int L, int R, int o, int ql, int qr, LL v) {
pushdown(L, R, o);
if(ql <= L && R <= qr){ addv[o] += v; if(addv[o] >= MOD) addv[o] -= MOD; }
else {
int M = L + R >> 1, lc = o << 1, rc = lc | 1;
if(ql <= M) update2(L, M, lc, ql, qr, v);
if(qr > M) update2(M+1, R, rc, ql, qr, v);
}
maintain(L, R, o);
return ;
}
LL query(int L, int R, int o, int ql, int qr) {
pushdown(L, R, o);
if(ql <= L && R <= qr) return (sumv[o] * timv[o] % MOD + addv[o] * (LL)(R - L + 1) % MOD) % MOD;
int M = L + R >> 1, lc = o << 1, rc = lc | 1;
LL ans = 0;
if(ql <= M){ ans += query(L, M, lc, ql, qr); if(ans >= MOD) ans -= MOD; }
if(qr > M){ ans += query(M+1, R, rc, ql, qr); if(ans >= MOD) ans -= MOD; }
return ans;
}
int main() {
n = read(); MOD = read();
for(int i = 1; i <= n; i++) val[i] = read() % MOD;
build(1, n, 1);
int q = read();
while(q--) {
int tp = read(), ql = read(), qr = read(), v;
if(tp == 1) {
v = read() % MOD;
update1(1, n, 1, ql, qr, v);
}
if(tp == 2) {
v = read() % MOD;
update2(1, n, 1, ql, qr, v);
}
if(tp == 3) printf("%lld\n", query(1, n, 1, ql, qr));
}
return 0;
}

浙公网安备 33010602011771号