Daimayuan Online Judge 线段树打标记2

\(n\) 个数 \(a_1, a_2, \cdots, a_n\)
支持 \(q\) 个操作:

  1. 1 l r d ,令所有的 \(a_i(l \leq i \leq r)\) 加上 \(d\)
  2. 2 l r d ,令所有的 \(a_i(l \leq i \leq r)\) 乘上 \(d\)
  3. 3 l r d ,令所有的 \(a_i(l \leq i \leq r)\) 等于 \(d\)
  4. 4 l r ,查询 \((\sum_{i = l}^{r} a_i) \mod (10^9 + 7)\)

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

  1. 信息需要区间值和 \(sum\) ,区间大小 \(sz\) (维护和且区间加时必要)。
  2. 标记设计为 \(val \times mul + add\) 。不问为什么,问就是典。
  3. 合并:(以下默认模意义下)
    1. 信息与信息合并:\(now.sum = l.sum + r.sum\)\(now.sz = l.sz + r.sz\)
    2. 信息与标记合并:\(now.sum = f.sum \times t.mul + f.sz \times t.add\)
    3. 标记与标记合并:
      1. 非常需要注意标记合并需要按照先后顺序,比如 \(((a \times 2) + 3) \times 4 + 5\)\(((a \times 4) + 5) \times 2 + 3\) 分别为 \(8a + 12\)\(8a + 15\) ,显然不同。
      2. \(((a \times t1.mul) + t1.add) \times t2.mul + t2.add = (a \times t1.mul) \times t2.mul + (t1.add) \times t2.mul + t2.add\) 。于是有 \(now.mul = t1.mul \times t2.mul\)\(now.add = t1.add \times t2.mul + t2.add\)
  4. 注意多个标记时的初始化,\(a = a \times 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};
	}
}

只需要推理出 \(Info\)\(Tag\) 与目标信息的关系。

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

注意 \(build\) 里有 \(Info\)\(Tag\) 的初始化,\(pushdown\) 里有 \(Tag\) 初始化和 \(Tag\) 非空的判断。

view
#include <bits/stdc++.h>
typedef long long i64;

const int MOD = 1E9 + 7;

const int MAXN = 200005;
int a[MAXN];

struct S {
  i64 sum, sz;
  S(){}
  S(i64 _sum, i64 _sz) : sum(_sum), sz(_sz) {}
  void init(int x, int a[]) { *this = S(a[x], 1); }
};

struct T {
  i64 mul, add;
  T() : mul(1), add(0){}
  T(i64 _mul, i64 _add) : mul(_mul), add(_add){}
} I;

S operator + (const S &LHS, const S &RHS) {
  S ret;
  ret = { ( LHS.sum + RHS.sum ) % MOD, LHS.sz + RHS.sz };
  return ret;
}

T operator * (const T &LHS, const T &RHS) {
  T ret;
  ret = { ( LHS.mul * RHS.mul ) % MOD, ( LHS.add * RHS.mul + RHS.add ) % MOD };
  return ret;
}

S operator >> (const T &t, const S &f) {
  S ret;
  ret = { ( ( f.sum * t.mul ) % MOD + ( f.sz * t.add ) % MOD ) % MOD, f.sz };
  return ret;
}

#define ls (id << 1)
#define rs (id << 1 | 1)

struct Node {
  S f;
  T t;
} seg[MAXN * 4];

void upd(int id) {
  seg[id].f = seg[ls].f + seg[rs].f;
} 

void psd(int id) {
  void setT(int, T);
  setT(ls, seg[id].t );
  setT(rs, seg[id].t );
  seg[id].t = I;
}

void setT(int id, T t) {
  seg[id].f = t >> seg[id].f;
  seg[id].t = seg[id].t * t;
}

void build(int id, int l, int r) {
  if (l == r) {
    seg[id].f.init(l, a);
    return;
  }
  int mid = ( l + r ) >> 1;
  build(ls, l, mid );
  build(rs, mid + 1, r );
  upd(id);
} 

S ask(int id, int l, int r, int ql, int qr) {
  if (l == ql && r == qr) {
    return seg[id].f;
  }
  psd(id);
  int mid = ( l + r ) >> 1;
  if ( qr <= mid ) return ask(ls, l, mid, ql, qr );
  else if ( ql > mid ) return ask(rs, mid + 1, r, ql, qr );
  else return ask(ls, l, mid, ql, mid ) + ask(rs, mid + 1, r, mid + 1, qr);
}

void edt(int id, int l, int r, int ql, int qr, T t) {
  if (l == ql && r == qr) {
    setT( id, t );
    return;
  }
  psd(id);
  int mid = ( l + r ) >> 1;
  if ( qr <= mid ) edt(ls, l, mid, ql, qr, t );
  else if ( ql > mid) edt(rs, mid + 1, r, ql, qr, t );
  else edt(ls, l, mid, ql, mid, t ), edt(rs, mid + 1, r, mid + 1, qr, t );
  upd(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;
      edt(1, 1, n, l, r, {1, d});
    } else if ( typ == 2 ) {
      int l, r, d; std::cin >> l >> r >> d;
      edt(1, 1, n, l, r, {d, 0});
    } else if ( typ == 3 ) {
      int l, r, d; std::cin >> l >> r >> d;
      edt(1, 1, n, l, r, {0, d});
    } else {
      int l, r; std::cin >> l >> r;
      auto ans = ask(1, 1, n, l, r);
      std::cout << ans.sum << '\n';
    }
  }
  return 0;
}
posted @ 2023-08-29 21:08  03Goose  阅读(74)  评论(0)    收藏  举报