[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。
分析:对于一次乘法操作,把乘法标记和加法标记都乘这个数即可,其他的正常操作。
代码
#include <cstdio>
#define N 500000
#define ll long long
using namespace std;
struct tree
{
int l, r;
ll add, mul, sum;
}tr[N];
ll a[N],mo,ans;
int n,m;
void build(int p)
{
tr[p].mul = 1;
if (tr[p].l == tr[p].r)
{
tr[p].sum = a[tr[p].l];
return;
}
int mid = (tr[p].l + tr[p].r) / 2;
tr[p * 2].l = tr[p].l;
tr[p * 2].r = mid;
tr[p * 2 + 1].l =mid + 1;
tr[p * 2 + 1].r = tr[p].r;
build(p * 2);
build(p * 2 + 1);
tr[p].sum = (tr[p * 2].sum + tr[p * 2 + 1].sum) % mo;
}
void down(int p)
{
tr[p * 2].add = ((tr[p].mul * tr[p * 2].add) % mo + tr[p].add) % mo;
tr[p * 2].mul = tr[p * 2].mul * tr[p].mul % mo;
tr[p * 2].sum = ((tr[p].mul * tr[p * 2].sum % mo) + tr[p].add * (tr[p * 2].r - tr[p * 2].l + 1) % mo) % mo;
tr[p * 2 + 1].add = ((tr[p].mul * tr[p * 2 + 1].add) % mo + tr[p].add) % mo;
tr[p * 2 + 1].mul = tr[p * 2 + 1].mul * tr[p].mul % mo;
tr[p * 2 + 1].sum = ((tr[p].mul * tr[p * 2 + 1].sum % mo) + tr[p].add * (tr[p * 2 + 1].r - tr[p * 2 + 1].l + 1) % mo) % mo;
tr[p].mul = 1;
tr[p].add = 0;
}
void find(int p, int x, int y)
{
if (tr[p].l == x && tr[p].r == y)
{
ans = (ans + tr[p].sum) % mo;
return;
}
down(p);
int mid = (tr[p].l + tr[p].r) / 2;
if (y <= mid) find(p * 2, x, y);
else if (x > mid) find(p * 2 + 1, x, y);
else find(p * 2, x, mid), find(p * 2 + 1, mid + 1, y);
}
void change(int p, int x, int y, ll val, int op)
{
if (tr[p].l == x && tr[p].r == y)
{
if (op == 1)
{
tr[p].mul = tr[p].mul * val % mo;
tr[p].add = tr[p].add * val % mo;
tr[p].sum = val * tr[p].sum % mo;
}
else tr[p].add = (tr[p].add + val) % mo, tr[p].sum = (tr[p].sum + val * (tr[p].r - tr[p].l + 1) % mo) % mo;
return;
}
down(p);
int mid = (tr[p].l + tr[p].r) / 2;
if (y <= mid) change(p * 2, x, y, val, op);
else if (x > mid) change(p * 2 + 1, x, y, val, op);
else change(p * 2, x, mid, val, op), change(p * 2 + 1, mid + 1, y, val, op);
tr[p].sum = (tr[p * 2].sum + tr[p * 2 + 1].sum) % mo;
}
int main()
{
scanf("%d%lld", &n, &mo);
for (int i = 1; i <= n; i++)
scanf("%lld", &a[i]);
tr[1].l = 1;
tr[1].r = n;
build(1);
scanf("%d", &m);
for (int i = 1; i <= m; i++)
{
int op, x, y;
scanf("%d%d%d", &op, &x, &y);
if (op == 3)
{
ans = 0;
find(1, x, y);
printf("%lld\n", ans);
}
else
{
ll z = 0;
scanf("%lld", &z);
change(1, x, y, z, op);
}
}
}