Daimayuan Online Judge 线段树打标记2

n 个数 a1,a2,,an
支持 q 个操作:

  1. 1 l r d ,令所有的 ai(lir) 加上 d
  2. 2 l r d ,令所有的 ai(lir) 乘上 d
  3. 3 l r d ,令所有的 ai(lir) 等于 d
  4. 4 l r ,查询 (i=lrai)mod(109+7)

一:确定维护的信息,确定修改信息需要的标记。确定期间的合并。

  1. 信息需要区间值和 sum ,区间大小 sz (维护和且区间加时必要)。
  2. 标记设计为 val×mul+add 。不问为什么,问就是典。
  3. 合并:(以下默认模意义下)
    1. 信息与信息合并:now.sum=l.sum+r.sumnow.sz=l.sz+r.sz
    2. 信息与标记合并:now.sum=f.sum×t.mul+f.sz×t.add
    3. 标记与标记合并:
      1. 非常需要注意标记合并需要按照先后顺序,比如 ((a×2)+3)×4+5((a×4)+5)×2+3 分别为 8a+128a+15 ,显然不同。
      2. ((a×t1.mul)+t1.add)×t2.mul+t2.add=(a×t1.mul)×t2.mul+(t1.add)×t2.mul+t2.add 。于是有 now.mul=t1.mul×t2.mulnow.add=t1.add×t2.mul+t2.add
  4. 注意多个标记时的初始化,a=a×1+0 ,于是 build 时初始化 t={1,0}
// 主要是确定 Info 和 Tag 的信息
struct Info {
ll sum, sz;
};
struct Tag {
ll mul, add;
};
struct Node {
Info f;
Tag t;
} seg[N * 4];
// 确定他们的合并方式
Info operator + (const Info &l, const Info &r) {
Info ret;
ret = { ( l.sum + r.sum ) % mod, l.sz + r.sz };
return ret;
}
Info operator + (const Info &f, const Tag &t) {
Info ret;
ret = { ( ( f.sum * t.mul ) % mod + ( f.sz * t.add ) % mod ) % mod, f.sz };
return ret;
}
Tag operator + (const Tag &t1, const Tag &t2) {
Tag ret;
ret = { ( t1.mul * t2.mul ) % mod, ( t1.add * t2.mul + t2.add ) % mod };
return ret;
}
void update(int id) {
seg[id].f = seg[ id * 2 ].f + seg[ id * 2 + 1].f;
}
void settag(int id, Tag t) {
seg[id].f = seg[id].f + t;
seg[id].t = seg[id].t + t;
}
void pushdown(int id) {
if (seg[id].t.mul != 1 || seg[id].t.add != 0) { // 标记非空,一个习惯
settag( id * 2, seg[id].t );
settag( id * 2 + 1, seg[id].t );
seg[id].t = {1, 0};
}
}

只需要推理出 InfoTag 与目标信息的关系。

然后改一下 InfoTag 、合并方式,调整一下初始化,就可以直接贴代码了。

注意 build 里有 InfoTag 的初始化,pushdown 里有 Tag 初始化和 Tag 非空的判断。

view
#include <bits/stdc++.h>
typedef long long ll;
const int N = 200005;
const int mod = 1E9 + 7;
int a[N];
struct Info {
ll sum, sz;
};
struct Tag {
ll mul, add;
};
struct Node {
Info f;
Tag t;
} seg[N * 4];
Info operator + (const Info &l, const Info &r) {
Info ret;
ret = { ( l.sum + r.sum ) % mod, l.sz + r.sz };
return ret;
}
Info operator + (const Info &f, const Tag &t) {
Info ret;
ret = { ( ( f.sum * t.mul ) % mod + ( f.sz * t.add ) % mod ) % mod, f.sz };
return ret;
}
Tag operator + (const Tag &t1, const Tag &t2) {
Tag ret;
ret = { ( t1.mul * t2.mul ) % mod, ( t1.add * t2.mul + t2.add ) % mod };
return ret;
}
void update(int id) {
seg[id].f = seg[ id * 2 ].f + seg[ id * 2 + 1].f;
}
void settag(int id, Tag t) {
seg[id].f = seg[id].f + t;
seg[id].t = seg[id].t + t;
}
void pushdown(int id) {
if (seg[id].t.mul != 1 || seg[id].t.add != 0) { // 标记非空,一个习惯
settag( id * 2, seg[id].t );
settag( id * 2 + 1, seg[id].t );
seg[id].t = {1, 0};
}
}
void build(int id, int l, int r) {
seg[id].t = {1, 0};
if (l == r) {
seg[id].f = {a[l], 1};
}
else {
int mid = ( l + r ) >> 1;
build( id * 2, l, mid );
build( id * 2 + 1, mid + 1, r );
update(id);
}
}
Info query(int id, int l, int r, int ql, int qr) {
if (l == ql && r == qr) {
return seg[id].f;
}
else {
pushdown(id);
int mid = ( l + r ) >> 1;
if ( qr <= mid ) return query( id * 2, l, mid, ql, qr );
else if ( ql > mid ) return query( id * 2 + 1, mid + 1, r, ql, qr );
else return query( id * 2, l, mid, ql, mid ) + query( id * 2 + 1, mid + 1, r, mid + 1, qr);
}
}
void modify(int id, int l, int r, int ql, int qr, Tag t) {
if (l == ql && r == qr) {
settag( id, t );
}
else {
pushdown(id);
int mid = ( l + r ) >> 1;
if ( qr <= mid ) modify( id * 2, l, mid, ql, qr, t );
else if ( ql > mid) modify( id * 2 + 1, mid + 1, r, ql, qr, t );
else modify( id * 2, l, mid, ql, mid, t ), modify( id * 2 + 1, mid + 1, r, mid + 1, qr, t );
update(id);
}
}
int main() {
int n, q;
std::cin >> n >> q;
for (int i = 1; i <= n; i++) std::cin >> a[i];
build(1, 1, n);
for (int i = 1; i <= q; i++) {
int typ; std::cin >> typ;
if ( typ == 1 ) {
int l, r, d; std::cin >> l >> r >> d;
modify(1, 1, n, l, r, {1, d});
}
else if ( typ == 2 ) {
int l, r, d; std::cin >> l >> r >> d;
modify(1, 1, n, l, r, {d, 0});
}
else if ( typ == 3 ) {
int l, r, d; std::cin >> l >> r >> d;
modify(1, 1, n, l, r, {0, d});
}
else {
int l, r; std::cin >> l >> r;
auto ans = query(1, 1, n, l, r);
std::cout << ans.sum << '\n';
}
}
return 0;
}
posted @   zsxuan  阅读(22)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示