专题二树形结构 M - 维护序列
- 题目
题目描述原题来自:AHOI 2009
老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。
有长为 的数列,不妨设为 a1,a2,⋯ ,ana_1,a_2,\cdots ,a_n。有如下三种操作形式:
- 把数列中的一段数全部乘一个值;
- 把数列中的一段数全部加一个值;
- 询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模 PP 的值。
第一行两个整数 和 ;
第二行含有 个非负整数,从左到右依次为 a1,a2,⋯ ,ana_1,a_2,\cdots ,a_n;
第三行有一个整数 ,表示操作总数;
从第四行开始每行描述一个操作,输入的操作有以下三种形式:
- 操作 :
1 t g c
,表示把所有满足 t≤i≤gt\le i\le g 的 aia_i 改为 ai×ca_i\times c; - 操作 :
2 t g c
,表示把所有满足 t≤i≤gt\le i\le g 的 aia_i 改为 ai+ca_i+c; - 操作 :
3 t g
,询问所有满足 t≤i≤gt\le i\le g 的 aia_i 的和模 的值。
同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。
输出格式对每个操作 ,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。
样例Inputcopy Outputcopy 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
初始时数列为 {1,2,3,4,5,6,7}{1,2,3,4,5,6,7};
经过第 1 次操作后,数列为 {1,10,15,20,25,6,7}{1,10,15,20,25,6,7};
对第 2 次操作,和为 10+15+20=4510+15+20=45,模 的结果是 22;
经过第 3 次操作后,数列为 {1,10,24,29,34,15,16}{1,10,24,29,34,15,16};
对第 4 次操作,和为 1+10+24=351+10+24=35,模 的结果是 3535;
对第 5 次操作,和为 29+34+15+16=9429+34+15+16=94,模 的结果是 88。
数据范围与提示对于全部测试数据,1≤t≤g≤n,0≤c,ai≤109,1≤P≤109+71\le t\le g\le n,0\le c,a_i\le 10^9,1\le P\le 10^9+7。
- 思路
对数据进行加法、乘法、模的操作,加法乘法各需要一个懒惰标记,乘法的懒惰标记要初始化为1
注意乘法操作的时候节点值和所有懒惰标记都要一起乘,数据的每一步加减乘除之后都要模一下 - 代码
#include<cstdio> #include<iostream> #include<string> #include<cstring> #include<algorithm> using namespace std; #define clear(a,x) memset(a,x,sizeof(a)) #define ll long long ll d[1000000],la[1000000],lm[1000000],a[1000005];//区间值,加法乘法懒惰标记,原始值 ll n,q,mod; void pd(ll i, ll s, ll t) { ll l = (i << 1), r = (i << 1) + 1, mid = s + ((t - s) >> 1); if (lm[i] != 1) { lm[l] *= lm[i];lm[l] %= mod; lm[r] *= lm[i];lm[r] %= mod; la[l] *= lm[i];la[l] %= mod; la[r] *= lm[i];la[r] %= mod; d[l] *= lm[i];d[l] %= mod; d[r] *= lm[i];d[r] %= mod; lm[i] = 1; } if (la[i]) { d[l] += la[i] * (mid - s + 1);d[l] %= mod; d[r] += la[i] * (t - mid);d[r] %= mod; la[l] += la[i];la[l] %= mod; la[r] += la[i];la[r] %= mod; la[i] = 0; } return; } void build(ll s, ll t, ll p) { if (s == t) { d[p] = a[s]; lm[p] = 1; return; } ll m = s + ((t - s) >> 1); build(s, m, p * 2), build(m + 1, t, p * 2 + 1); d[p] = d[p * 2] + d[(p * 2) + 1]; lm[p] = 1; } void update(ll l, ll r, ll c, ll s, ll t, ll p) { if (l <= s && t <= r) { d[p] += (t - s + 1) * c, la[p] += c; d[p] %= mod, la[p] %= mod; return; } ll m = s + ((t - s) >> 1); pd(p,s,t); if (l <= m) update(l, r, c, s, m, p * 2); if (r > m) update(l, r, c, m + 1, t, p * 2 + 1); d[p] = (d[p * 2] + d[p * 2 + 1]) % mod; } void updatem(ll l, ll r, ll c, ll s, ll t, ll p) { if (l <= s && t <= r) { d[p] *= c, lm[p] *= c, la[p] *= c; d[p] %= mod, lm[p] %= mod, la[p] %= mod; return; } ll m = s + ((t - s) >> 1); pd(p,s,t); if (l <= m) updatem(l, r, c, s, m, p * 2); if (r > m) updatem(l, r, c, m + 1, t, p * 2 + 1); d[p] = (d[p * 2] + d[p * 2 + 1]) % mod; } ll getsum(ll l, ll r, ll s, ll t, ll p) { if (l <= s && t <= r) return d[p]; ll m = s + ((t - s) >> 1); pd(p,s,t); ll sum = 0; if (l <= m) sum += getsum(l, r, s, m, p * 2); sum %= mod; if (r > m) sum += getsum(l, r, m + 1, t, p * 2 + 1); return sum % mod; } int main() { scanf("%lld%lld",&n,&mod); clear(d,0); clear(la,0); for(int i=1;i<=n;i++){ scanf("%lld",&a[i]); } build(1,n,1); scanf("%lld",&q); ll op,x,y,z; while (q--) { cin >> op >> x >> y; if (op == 3) cout << getsum(x, y, 1, n, 1) <<endl; else if (op == 2) cin >> z, update(x, y, z, 1, n, 1); else cin >> z, updatem(x, y, z, 1, n, 1); } }