luogu P1438 无聊的数列
思路
区间\(L\)到\(R\)内加等差数列
已知首项为\(K\),公差为\(D\)
那么每一位加的数值为
\[K+(i-L)*D(L<=i<=R)
\]
\[K+i*D-L*D(L<=i<=R)
\]
\[K-L*D+i*D(L<=i<=R)
\]
我们可以分别加一下\(K-L*D\)和\(i*D\)
前者可以算出来,直接区间加就可以
后者的话,先维护一下\([L,R]\)内的下标和
结合律用一下,加上R*下标和就行了
update
修改的时候在区间\([L,R]\)内的贡献为
\[(K-L*D)*(R-L+1)+\sum_{L}^{R}*D
\]
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#define ls rt<<1
#define rs rt<<1|1
#define ll long long
#define FOR(i,a,b) for(int i=a;i<=b;++i)
using namespace std;
const int maxn = 1e5 + 7;
int read() {
int x = 0, f = 1; char s = getchar();
for (; s < '0' || s > '9'; s = getchar()) if (s == '-') f = -1;
for (; s >= '0' && s <= '9'; s = getchar()) x = x * 10 + s - '0';
return x * f;
}
struct node {
int l,r,size;
ll ans,lazy1,tot,lazy2;
}e[maxn<<2];
int n,m,a[maxn];
void pushup(int rt) {
e[rt].ans=e[ls].ans+e[rs].ans;
}
void pushdown(int rt) {
if(e[rt].lazy1) {
e[ls].ans+=e[ls].size*e[rt].lazy1;
e[rs].ans+=e[rs].size*e[rt].lazy1;
e[ls].lazy1+=e[rt].lazy1;
e[rs].lazy1+=e[rt].lazy1;
e[rt].lazy1=0;
}
if(e[rt].lazy2) {
e[ls].ans+=e[ls].tot*e[rt].lazy2;
e[rs].ans+=e[rs].tot*e[rt].lazy2;
e[ls].lazy2+=e[rt].lazy2;
e[rs].lazy2+=e[rt].lazy2;
e[rt].lazy2=0;
}
}
void build(int l,int r,int rt) {
e[rt].l=l,e[rt].r=r,e[rt].size=r-l+1;
if(l==r) {
e[rt].tot=l;
e[rt].ans=a[l];
return;
}
int mid=(e[rt].l+e[rt].r)>>1;
build(l,mid,ls);
build(mid+1,r,rs);
pushup(rt);
e[rt].tot=e[ls].tot+e[rs].tot;
}
void modfity_1(int L,int R,ll k,int rt) { // 区间加
if(L<=e[rt].l&&e[rt].r<=R) {
e[rt].ans+=k*e[rt].size;
e[rt].lazy1+=k;
return;
}
pushdown(rt);
int mid=(e[rt].l+e[rt].r)>>1;
if(L<=mid) modfity_1(L,R,k,ls);
if(R>mid) modfity_1(L,R,k,rs);
pushup(rt);
}
void modfity_2(int L,int R,ll k,int rt) { // 区间i*k
if(L<=e[rt].l&&e[rt].r<=R) {
e[rt].ans+=k*e[rt].tot;
e[rt].lazy2+=k;
return;
}
pushdown(rt);
int mid=(e[rt].l+e[rt].r)>>1;
if(L<=mid) modfity_2(L,R,k,ls);
if(R>mid) modfity_2(L,R,k,rs);
pushup(rt);
}
ll query(int L,int rt) {
if(e[rt].l==e[rt].r) {
return e[rt].ans;
}
pushdown(rt);
int mid=(e[rt].l+e[rt].r)>>1;
if(L<=mid) return query(L,ls);
else return query(L,rs);
}
int main() {
n=read(),m=read();
FOR(i,1,n) a[i]=read();
build(1,n,1);
FOR(i,1,m) {
int pd=read();
if(pd==1) {
int l=read(),r=read(),k=read(),d=read();
modfity_1(l,r,k-l*d,1);
modfity_2(l,r,d,1);
} else {
int x=read();
printf("%lld\n",query(x,1));
}
}
return 0;
}