@Aonrbet
2020-07-06T02:39:39.000000Z
字数 3903
阅读 483
Study
#include <bits/stdc++.h>using namespace std;/*如果人可以长尾巴会觉得有点难为情呢因为只要和你在一起,我总会忍不住摇尾巴吧*/const int maxn = 1e6 + 10;#define ls(now) (now << 1)#define rs(now) (now<<1|1)#define mid ((l + r) >> 1)int n, m, a[maxn];struct seg_tree{struct nodes{long long l, r, sum, tag;long long get(){return sum + (r - l + 1) * tag;}}node[maxn];void up(int now){return (void)(node[now].sum = node[ls(now)].get() + node[rs(now)].get());}void down(int now){return (void)(node[ls(now)].tag += node[now].tag, node[rs(now)].tag += node[now].tag, node[now].tag = 0);}void bulid(int l, int r, int now){node[now].l = l, node[now].r = r;if(l == r) return (void)(node[now].sum = a[l]);bulid(l, mid, ls(now)), bulid(mid+1, r, rs(now));up(now);}void chenge(int l, int r, int now, int val){if(node[now].r < l or node[now].l > r) return;if(l <= node[now].l and node[now].r <= r) return (void)(node[now].tag += val);down(now);chenge(l, r, ls(now), val), chenge(l, r, rs(now), val);up(now);}void query(int l, int r, int now, long long &ans){if(l > node[now].r or r < node[now].l) return;if(l <= node[now].l and node[now].r <= r) return (void)(ans += node[now].get());down(now);query(l, r, ls(now), ans), query(l, r, rs(now), ans);up(now);}}tree;signed main(){scanf("%d%d", &n, &m);for(int i = 1; i <= n; i ++){scanf("%d", &a[i]);}tree.bulid(1, n, 1);for(int cmp, x, y, z; m ; m --){scanf("%d", &cmp);if(cmp == 1){scanf("%d%d%d", &x, &y, &z);tree.chenge(x, y, 1, z);}if(cmp == 2){long long ans = 0;scanf("%d%d", &x, &y);tree.query(x, y, 1, ans);printf("%lld\n", ans);}}return 0;}
加法和乘法顺序不一样会导致不同的结果
比如: 不等于
而在记录懒标记的时候,加法和乘法两种标记放到一起,并不知道哪个先,哪个后。
所以要确定一个优先级
我们分析一下两种顺序:
先加后乘 : =
先乘后加:
比较一下,发现,上面的先加后乘相当于下面的式子,在加法上面多乘了一个
所以,我们只要是先加后乘的式子,只要加一个就可以转化为先乘后加的式子
具体的操作就是在添加乘法标记的时候,把加法标记就好了
所以,我们就定了一个总顺序:先乘后加(摘自luogu博客)
然后在down下放标记的时候,左右儿子的加法标记传递也要保持先乘后加的顺序,即 :
void down(int now){t[ls(now)].tmp = (t[ls(now)].tmp*t[now].tmp)%p;t[rs(now)].tmp = (t[rs(now)].tmp*t[now].tmp)%p;t[ls(now)].tag = (t[ls(now)].tag*t[now].tmp)%p;t[rs(now)].tag = (t[rs(now)].tag*t[now].tmp)%p;t[ls(now)].tag = (t[ls(now)].tag+t[now].tag)%p;t[rs(now)].tag = (t[rs(now)].tag+t[now].tag)%p;t[now].tag = 0, t[now].tmp = 1;return;}
解决方法:先乘后加
//对于每一次的区间乘val,我们对在此次操作前做的区间加也乘上这次的valt[now].tmp *= val, t[now].tag *= val
完美的解决了问题
#include <bits/stdc++.h>using namespace std;/*如果人可以长尾巴会觉得有点难为情呢因为只要和你在一起,我总会忍不住摇尾巴吧*/const int maxn = 1e6 + 10;#define ls(now) (now << 1)#define rs(noe) (now<<1|1)#define mid ((l + r) >> 1)int n, m, p, a[maxn];long long ans;struct seg_tree{struct nodes{long long l, r, sum, tag, tmp;nodes(){tmp = 1;tag = 0;}long long get(){return (((sum%p)*tmp%p)%p + ((r-l+1)*tag)%p);}}t[maxn];void up(int now){return (void)(t[now].sum = t[ls(now)].get() + t[rs(now)].get());}void down(int now){t[ls(now)].tmp = (t[ls(now)].tmp*t[now].tmp)%p;t[rs(now)].tmp = (t[rs(now)].tmp*t[now].tmp)%p;t[ls(now)].tag = (t[ls(now)].tag*t[now].tmp)%p;t[rs(now)].tag = (t[rs(now)].tag*t[now].tmp)%p;t[ls(now)].tag = (t[ls(now)].tag+t[now].tag)%p;t[rs(now)].tag = (t[rs(now)].tag+t[now].tag)%p;t[now].tag = 0, t[now].tmp = 1;return;}void bulid(int l, int r, int now){t[now].l = l, t[now].r = r;if(l == r) return (void)(t[now].sum = a[l]);bulid(l, mid, ls(now)), bulid(mid+1, r, rs(now));up(now);}void chenge(int l, int r, int now, int val){if(r < t[now].l or l > t[now].r) return;if(l <= t[now].l and t[now].r <= r) return (void)(t[now].tag += val);down(now);chenge(l, r, ls(now), val), chenge(l, r, rs(now), val);up(now);}void change(int l, int r, int now, int val){if(r < t[now].l or l > t[now].r) return;if(l <= t[now].l and t[now].r <= r) return (void)(t[now].tmp *= val, t[now].tag *= val);down(now);change(l, r, ls(now), val), change(l, r, rs(now), val);up(now);}void query(int l, int r, int now, long long &ans){if(r < t[now].l or l > t[now].r) return;if(l <= t[now].l and t[now].r <= r) return (void)(ans += t[now].get(), ans %= p);down(now);query(l, r, ls(now), ans), query(l, r, rs(now), ans);up(now);}}tree;signed main(){scanf("%d%d%d", &n, &m, &p);for(int i = 1; i <= n; i ++){scanf("%d", &a[i]);}tree.bulid(1, n, 1);for(int cmp, x, y, z; m; m --){scanf("%d", &cmp);if(cmp == 1){scanf("%d%d%d", &x, &y, &z);tree.change(x, y, 1, z);}if(cmp == 2){scanf("%d%d%d", &x, &y, &z);tree.chenge(x, y, 1, z);}if(cmp == 3){scanf("%d%d", &x, &y);tree.query(x, y, 1, ans);printf("%lld\n", ans);ans = 0;}}return 0;}