无聊的数列
sol:
线段树维护等差数列。lazy_tag维护首项和公差。pushdown时将首项和公差累加到子节点上去。应重新计算右节点的首项。
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int N = 1e5 + 100;
struct Tree {
int l, r;
int v, fir, d;
} tr[N << 2];
int n, m;
int a[N];
void build(int u, int l, int r) {
tr[u].l = l, tr[u].r = r;
if( l == r) {
tr[u].v = a[l];
return;
}
int mid = tr[u].l + tr[u].r >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
}
void pushdown(int u) {
if( tr[u].fir || tr[u].d) {
Tree & ls = tr[u << 1], &rs = tr[u << 1 | 1];
ls.fir += tr[u].fir;
ls.d += tr[u].d;
ls.v += tr[u].fir;
int first = tr[u].fir + (ls.r - ls.l + 1) * tr[u].d;//右侧的首项
rs.fir += first;
rs.d += tr[u].d;
rs.v += first;
tr[u].d = 0;
tr[u].fir = 0;
}
}
void change(int u, int l, int r, int k, int d) {
if( tr[u].l >= l && tr[u].r <= r) {
int first = k + (tr[u].l - l) * d;
tr[u].fir += first;
tr[u].d += d;
tr[u].v += first;
return;
}
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if( l <= mid) change(u << 1, l, r, k, d);
if( r > mid) change(u << 1 | 1, l, r, k, d);
}
int query(int u, int k) {
if( tr[u].l == tr[u].r) {
return tr[u].v;
}
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if( k <= mid)
return query(u << 1, k);
else
return query(u << 1 | 1, k);
}
int main()
{
// freopen("E:\\data.in.txt", "r", stdin);
// freopen("E:\\data.out.txt", "w", stdout);
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++) {
scanf("%d", &a[i]);
}
build(1, 1, n);
while(m --) {
int opt, l, r, k, d;
scanf("%d", &opt);
if( opt == 1) {
scanf("%d%d%d%d", &l, &r, &k, &d);
change(1, l, r, k, d);
}
else {
scanf("%d", &k);
printf("%d\n", query(1, k));
}
}
return 0;
}