做法,线段树
线段树维护一个等差序列。
懒标记:记录当前的k值,记录k值所在位置

#include <iostream>
#include <cstdio>

using namespace std;

#define int long  long

const int N = 200010;

struct Node {
  int l, r, sum, add, t;
}tr[N * 4];

int n, m;
int w[N];

void pushup(Node &c, Node &a, Node &b) {
  c.sum = a.sum + b.sum;
}

void pushup(int u) {
  pushup(tr[u], tr[u << 1], tr[u << 1 | 1]);
}

//u表示修改的线段树节点编号,l表示k所在的位置
void add(int u, int k, int l) {
  int len = tr[u].r - tr[u].l + 1;
  tr[u].sum = len * (tr[u].l + (k - l) + tr[u].r + (k - l)) / 2;
  tr[u].add = k, tr[u].t = l;
}

void pushdown(int u) {
  if (!tr[u].add) return;
  add(u << 1, tr[u].add, tr[u].t);
  add(u << 1 | 1, tr[u].add, tr[u].t);
  tr[u].add = 0; tr[u].t = 0;
}

void build(int u, int l, int r) {
  if (l == r) {
    tr[u] = {l, l, w[l], 0};
    return;
  }

  tr[u] = {l, r};
  int mid = l + r >> 1;
  build(u << 1, l, mid);
  build(u << 1 | 1, mid + 1, r);

  pushup(u);
}

void change(int u, int l, int r, int k) {
  if (l <= tr[u].l && tr[u].r <= r) {
    add(u, k, l);
    return;
  }
  pushdown(u);

  int mid = tr[u].l + tr[u].r >> 1;
  if (l <= mid) change(u << 1, l, r, k);
  if (r > mid) change( u << 1 | 1, l, r, k);
  pushup(u);

}

int query(int u, int l, int r) {
  if (l <= tr[u].l && tr[u].r <= r) return tr[u].sum;
  pushdown(u);

  int mid = tr[u].l + tr[u].r >> 1;
  int sum = 0;
  if (l <= mid) sum += query(u << 1, l, r);
  if (r > mid) sum += query(u << 1 | 1, l, r);
  return sum;
}

signed main() {
  scanf("%lld%lld", &n, &m);
  for (int i = 1; i <= n; i ++ ) scanf("%lld", &w[i]);

  build(1, 1, n);

  while (m -- ) {
    int op, l, r, k;
    scanf("%lld%lld%lld", &op, &l, &r);

    if (op == 1) {
      scanf("%lld", &k);
      change(1, l, r, k);
    }
    else {
      printf("%lld\n", query(1, l, r));
    }
  }
  return 0;
}