标记幺半群左作用在信息幺半群上的代数结构

标记幺半群 \(T\) 左作用在信息幺半群 \(S\) 上的代数结构: \((T, \times, 1_{T}, S, +, 0_{S}, \circ)\)

对于信息幺半群 \((S, +, 0_{S})\) ,满足:

  • 封闭性:\(\forall x, y \in S\)\(x + y \in S\)
  • 结合律:\(\forall x, y, z \in S\)\((x + y) + z = x + (y + z)\)
  • 存在单位元:\(\forall x \in S, \exists 0_{S} \in S\)\(x + 0_{S} = 0_{S} + x\)

对于标记幺半群 \((T, \times, 1_{T})\) ,满足:

  • 封闭性:\(\forall a, b \in T\)\(a \times b \in T\)
  • 结合律:\(\forall a, b, z \in S\)\((a \times b) \times c = a \times (b \times c)\)
  • 存在单位元:\(\forall a \in T, \exists 1_{T} \in T\)\(a \times 1_{T} = 1_{T} \times a\)

对于 \(T\) 左作用在 \(S\) ,满足:

\[T \circ S : T \times S \rightarrow S \]

以下是 \((T, \times, 1_{T}, S, +, 0, \circ)\) 框架:
有时候传入数组的地址: const int a[] 可以考虑换成浅拷贝 vector :const std::vector<int> &a

view
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;
}

以下是线段树模板,基本无需修改,但初始化信息时需要传入数组地址,默认名字是 a 。

view
##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);
}
posted @ 2025-12-08 10:45  03Goose  阅读(6)  评论(0)    收藏  举报