做题记录整理线段树1 P1438 无聊的数列(2022/9/19)
一眼差分
原序列:0 0 0 0 0 0
差分序列:0 0 0 0 0 0
等差序列:2 4 6 8 10
加上等差数列后的序列:1 3 5 7 9 0
然后差分:1 2 2 2 2 -9
可以发现,首项所在的位置+k,其他位置+d,最后再全部剪掉就出来了
顺带一提,如果用树状数组应该会快一倍
#include<bits/stdc++.h>
using namespace std;
#define for1(i,a,b) for(ll i = a;i <=b;i++)
#define ll long long
ll n,a[500000],m,x,y,ji;
struct node{
ll l;
ll r;
ll lan;
ll zhi;
}s[500000*4];
void build(ll q,ll l,ll r)
{
s[q].lan=0;s[q].l=l;s[q].r=r;
if(l==r)
{
s[q].zhi=a[l];
return ;
}
ll mid = (l+r)/2;
build(q*2,l,mid);
build(q*2+1,mid+1,r);
s[q].zhi=s[q*2].zhi+s[q*2+1].zhi;
}
void chuan(ll q)
{
if(s[q].lan!=0)
{
s[q*2].zhi+=s[q].lan*(s[q*2].r-s[q*2].l+1);
s[q*2+1].zhi+=s[q].lan*(s[q*2+1].r-s[q*2+1].l+1);
s[q*2].lan+=s[q].lan;
s[q*2+1].lan+=s[q].lan;
s[q].lan = 0;
}
}
void xg(ll q,ll l,ll r,ll k)
{
ll mid = (s[q].l+s[q].r)/2;
if(s[q].l>=l&&s[q].r<=r)
{
s[q].zhi+=(s[q].r-s[q].l+1)*k;
s[q].lan+=k;
return ;
}
chuan(q);
if(l<=mid) xg(q*2,l,r,k);
if(r>mid) xg(q*2+1,l,r,k);
s[q].zhi=s[q*2].zhi+s[q*2+1].zhi;
}
ll qh(ll q,ll l,ll r)
{
ll mid = (s[q].l+s[q].r)/2;
if(s[q].l>=l&&s[q].r<=r)
{
return s[q].zhi;
}
chuan(q);
ll ans=0;
if(l<=mid) ans+=qh(q*2,l,r);
if(r>mid) ans+=qh(q*2+1,l,r);
return ans;
}
int main()
{
scanf("%lld%lld",&n,&m);
for1(i,1,n)scanf("%lld",&a[i]);
for(int i=n-1;i>0;i--)
a[i+1]=a[i+1]-a[i];
build(1,1,n);
ll k,d;
for1(i,1,m)
{
scanf("%d",&ji);
if(ji==1)
{
scanf("%d%d%lld%lld",&x,&y,&k,&d);
xg(1,x,x,k);
if(x+1<=y)
xg(1,x+1,y,d);
if(y+1<=n)
xg(1,y+1,y+1,-(k+(y-x)*d));
}
else{
scanf("%lld",&x);
printf("%lld\n",qh(1,1,x));
}
}
return 0;
}

浙公网安备 33010602011771号