【序列操作III】线段树
题目描述
给出序列 a1,a2,…an(0≤ai≤109),有关序列的四种操作:
1. al,al+1,…,ar(1≤l≤r≤n)加上 x(-103≤x≤103)
2. al,al+1,…,ar(1≤l≤r≤n)乘上 x(-103≤x≤103)
3. al,al+1,…,ar(1≤l≤r≤n)变成 x-al,x-al+1 ,…,x-ar(-103≤x≤103)
4. 求:
(即求:al+al+1+al+2+…+ar(1≤l≤r≤n)
所有操作均模 109+7
输入格式
第一行包含两个数 n(1≤n≤105)和 m(1≤m≤105),表示序列长度和操作次数
接下来一行包含 n 个数,空格隔开,表示 a1,a2,…,an 。
接下来 m 行,每行为以下 4 种格式之一:
-
- 0 l r x ,表示 al,al+1,…,ar 加上 x
- 1 l r x ,表示 al,al+1,…,ar 乘上 x
- 2 l r x ,表示 al,al+1,…,ar(1≤l≤r≤n)变成x-al,x-al+1 ,…,x-ar 。
- 3 l r ,求:
输出格式
对于每次询问,输出单独一行表示答案。
样例数据 1
输入
5 4
1 2 3 4 5
0 1 5 1
1 1 5 -1
2 1 5 1
3 5 5
输出
7
题目分析
同样是线段树裸题。维护区间加、乘标记,对于操作3,先乘-1,再加上x。
坑点同样是下标下放顺序:先乘后加,乘的时候add标记可以直接乘,而加的时候乘号标记必须已经下放。
code
#include<iostream> #include<cstring> #include<string> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cmath> #include<vector> using namespace std; const int N = 1e5 + 5, Mod = 1e9 + 7; typedef long long ll; int n, m, data[N]; struct node{ int len; ll sum, add, time; node():sum(0), time(1), len(0), add(0){} }; namespace SegTree{ node tr[N << 2]; inline void upt(int k){ tr[k].sum = (tr[k << 1].sum + tr[k << 1 | 1].sum) % Mod; } inline void build(int k, int l, int r){ tr[k].len = r - l + 1; if(l == r){ tr[k].sum = data[l]; tr[k].add = 0, tr[k].time = 1; return; } int mid = l + r >> 1, lc = k << 1, rc = k << 1 | 1; build(lc, l, mid); build(rc, mid + 1, r); upt(k); } inline void Add(int , int); inline void plus(ll &x, ll v){ x = (x + v) % Mod; while(x < 0) x += Mod; } inline void mul(ll &x, ll v){ x = (x * v) % Mod; while(x < 0) x += Mod; } inline void Time(int k, int v){ mul(tr[k].add , v); mul(tr[k].sum , v); mul(tr[k].time , v); } inline void Add(int k, int v){ plus(tr[k].sum, 1LL * tr[k].len * v); plus(tr[k].add, v); } inline void pushDown(int k){ int lc = k << 1, rc = k << 1 | 1; if(tr[k].time != 1){ if(tr[k].len > 1) Time(lc, tr[k].time), Time(rc, tr[k].time); tr[k].time = 1; } if(tr[k].add){ if(tr[k].len > 1) Add(lc, tr[k].add), Add(rc, tr[k].add); tr[k].add = 0; } } inline void modify(int k, int l, int r, int x, int y, int type, int v){ pushDown(k); if(x <= l && r <= y){ switch(type){ case 1: Add(k, v); break; case 2: Time(k, v); break; case 3: Time(k, -1), Add(k, v); break; } return; } int mid = l + r >> 1, lc = k << 1, rc = k << 1 | 1; if(x <= mid) modify(lc, l, mid, x, y, type, v); if(y > mid) modify(rc, mid + 1, r, x, y, type, v); upt(k); } inline int query(int k, int l, int r, int x, int y){ pushDown(k); if(x <= l && r <= y) return tr[k].sum; int mid = l + r >> 1, lc = k << 1, rc = k << 1 | 1, ret = 0; if(x <= mid) ret = (ret + query(lc, l, mid, x, y)) % Mod; if(y > mid) ret = (ret + query(rc, mid + 1, r, x, y)) % Mod; return ret; } }using namespace SegTree; inline int read(){ int i = 0, f = 1; char ch = getchar(); for(; (ch < '0' || ch > '9') && ch != '-'; ch = getchar()); if(ch == '-') f = -1, ch = getchar(); for(; ch >= '0' && ch <= '9'; ch = getchar()) i = (i << 3) + (i << 1) + (ch - '0'); return i * f; } inline void wr(int x){ if(x < 0) putchar('-'), x = -x; if(x > 9) wr(x / 10); putchar(x % 10 + '0'); } int main(){ n = read(), m = read(); for(int i = 1; i <= n; i++) data[i] = read(); build(1, 1, n); for(int i = 1; i <= m; i++){ int opt = read() + 1, a = read(), b = read(), c; if(opt == 1 || opt == 2 || opt == 3) c = read(), modify(1, 1, n, a, b, opt, c); else wr(query(1, 1, n, a, b)), putchar('\n'); } return 0; }