目录
百度解释
功能:
延迟区间加乘,加速区间查询。
个人看法:
将区间不断二分,记录每段二分后区间,直到成点。
同时可以用结构体辅助记录每一段的信息:左右结点(区间范围),区间和,懒惰标记。
结构:
1.根据初始数据建立线段树:函数build(1,1,n):将数组a[n]的数据放在线段树上
代码中: l:区间下标左极限。r:区间下标右极限。s:区间和。g:加法懒惰标记。gg:乘法懒惰标记。
2.加法(减法):函数add(1,x,y,k):在[x,y]区间(点)上加k
3.乘法:函数mul(1,x,y,k): [x,y]区间(点)上乘k
4.查询区间之和:函数search(1,x,y):返回[x,y]区间(点)之和
5.psuhdown(i)::先利用本结点的懒惰标记更新左右子结点的数据,并将本结点的懒惰标记放在左右子结点上,而本结点的懒惰标记恢复初始状态。
之所以懒惰,是因为控制了更新时机(只在将要遇到时)。
难点:
递归思想,二分,懒惰标记。
例题Tips:
1.位运算:
x>>1 x/2; x>>n x/pow(2,n);
x<<1 x*2; x<<1 x*pow(2,n);
2.懒惰标记:
同时有加乘懒惰标记时的标记使用顺序简单解释。
可以人为规定先后顺序。
先乘后加比先加后乘简单很多。
add:
if(l<=t[i].l&&t[i].r<=r)
{
t[i].g=(t[i].g+k)%p;
t[i].s=(t[i].s+k*(t[i].r-t[i].l+1))%p;
return ;
}
pushdown(i);
mul:
if(l<=t[i].l&&t[i].r<=r)
{
t[i].s=(t[i].s*k)%p;
t[i].g=(t[i].g*k)%p;
t[i].gg=(t[i].gg*k)%p;
return ;
}
pushdown(i);
void pushdown(LL i)
{
t[i<<1].s=(t[i<<1].s*t[i].gg+t[i].g*(t[i<<1].r-t[i<<1].l+1))%p;
t[(i<<1)+1].s=(t[(i<<1)+1].s*t[i].gg+t[i].g*(t[(i<<1)+1].r-t[(i<<1)+1].l+1))%p;
//
t[i<<1].gg=(t[i<<1].gg*t[i].gg)%p;
t[(i<<1)+1].gg=(t[(i<<1)+1].gg*t[i].gg)%p;
//
t[i<<1].g=(t[i<<1].g*t[i].gg+t[i].g)%p;
t[(i<<1)+1].g=(t[(i<<1)+1].g*t[i].gg+t[i].g)%p;
t[i].g=0;
t[i].gg=1;
}
例题1:加法+懒惰标记
题目背景
同时适用于
#include<bits/stdc++.h>
#define bbn 100005
// 注意bbn大小(会RE||ME)
using namespace std;
typedef long long int LL;
LL a[bbn];
struct T
{
LL l,r;
LL s,g;
} t[4*bbn];
void build(LL i,LL l,LL r)
{
t[i].l=l;
t[i].r=r;
if(l==r)
{
t[i].s=a[l];
return ;
}
LL mid=(l+r)>>1;
build(i<<1,l,mid);
build((i<<1)+1,mid+1,r);
t[i].s=t[i<<1].s+t[(i<<1)+1].s;
}
void pushdown(LL i)
{
if(t[i].g!=0)
{
t[i<<1].g+=t[i].g;
t[i<<1].s+=t[i].g*(t[i<<1].r-t[i<<1].l+1);
t[(i<<1)+1].g+=t[i].g;
t[(i<<1)+1].s+=t[i].g*(t[(i<<1)+1].r-t[(i<<1)+1].l+1);
t[i].g=0;
}
}
LL search(LL i,LL l,LL r)
{
if(l<=t[i].l&&t[i].r<=r)
{
return t[i].s;
}
if(t[i].r<l||t[i].l>r)
{
return 0;
}
pushdown(i);
LL sum=0;
LL mid=(t[i].l+t[i].r)>>1;
if(l<=mid)
{
sum+=search(i<<1,l,r);
}
if(r>=mid+1)
{
sum+=search((i<<1)+1,l,r);
}
return sum;
}
void add(LL i,LL l,LL r,LL k)
{
if(l<=t[i].l&&t[i].r<=r)
{
t[i].s+=k*(t[i].r-t[i].l+1);
t[i].g+=k;
return ;
}
pushdown(i);
LL mid=(t[i].l+t[i].r)>>1;
if(l<=mid)
{
add(i<<1,l,r,k);
}
if(r>=mid+1)
{
add((i<<1)+1,l,r,k);
}
t[i].s=t[i<<1].s+t[(i<<1)+1].s;
}
int main()
{
LL n,m;
scanf("%lld%lld",&n,&m);
for(LL i=1; i<=n; i++)
{
scanf("%lld",&a[i]);
}
build(1,1,n);
for(LL i=1; i<=m; i++)
{
LL judge;
scanf("%lld",&judge);
if(judge==1)
{
LL x,y,k;
scanf("%lld%lld%lld",&x,&y,&k);
add(1,x,y,k);
}
else if(judge==2)
{
LL x,y;
scanf("%lld%lld",&x,&y);
printf("%lld\n",search(1,x,y));
}
}
}
例题2:加法+乘法+取模+懒惰标记
题目背景
#include<bits/stdc++.h>
#define bbn 500001
using namespace std;
typedef long long int LL;
LL a[bbn];
LL n,m,p;
struct T
{
LL l,r;
LL s,g,gg;
} t[4*bbn];
void build(LL i,LL l,LL r)
{
t[i].l=l;
t[i].r=r;
t[i].g=0;
t[i].gg=1;
if(l==r)
{
t[i].s=a[l]%p;
return ;
}
LL mid=(l+r)>>1;
build(i<<1,l,mid);
build((i<<1)+1,mid+1,r);
t[i].s=(t[i<<1].s+t[(i<<1)+1].s)%p;
}
void pushdown(LL i)
{
t[i<<1].s=(t[i<<1].s*t[i].gg+t[i].g*(t[i<<1].r-t[i<<1].l+1))%p;
t[(i<<1)+1].s=(t[(i<<1)+1].s*t[i].gg+t[i].g*(t[(i<<1)+1].r-t[(i<<1)+1].l+1))%p;
//
t[i<<1].gg=(t[i<<1].gg*t[i].gg)%p;
t[(i<<1)+1].gg=(t[(i<<1)+1].gg*t[i].gg)%p;
//
t[i<<1].g=(t[i<<1].g*t[i].gg+t[i].g)%p;
t[(i<<1)+1].g=(t[(i<<1)+1].g*t[i].gg+t[i].g)%p;
t[i].g=0;
t[i].gg=1;
}
LL search(LL i,LL l,LL r)
{
if(t[i].r<l||t[i].l>r)
{
return 0;
}
if(l<=t[i].l&&t[i].r<=r)
{
return t[i].s;
}
pushdown(i);
return (search(i<<1,l,r)+search((i<<1)+1,l,r))%p;
}
void mul(LL i,LL l,LL r,LL k)
{
if(l<=t[i].l&&t[i].r<=r)
{
t[i].s=(t[i].s*k)%p;
t[i].g=(t[i].g*k)%p;
t[i].gg=(t[i].gg*k)%p;
return ;
}
pushdown(i);
LL mid=(t[i].l+t[i].r)>>1;
if(l<=mid)
{
mul(i<<1,l,r,k);
}
if(r>=mid+1)
{
mul((i<<1)+1,l,r,k);
}
t[i].s=(t[i<<1].s+t[(i<<1)+1].s)%p;
}
void add(LL i,LL l,LL r,LL k)
{
if(l<=t[i].l&&t[i].r<=r)
{
t[i].g=(t[i].g+k)%p;
t[i].s=(t[i].s+k*(t[i].r-t[i].l+1))%p;
return ;
}
pushdown(i);
LL mid=(t[i].l+t[i].r)>>1;
if(l<=mid)
{
add(i<<1,l,r,k);
}
if(r>=mid+1)
{
add((i<<1)+1,l,r,k);
}
t[i].s=(t[i<<1].s+t[(i<<1)+1].s)%p;
}
int main()
{
scanf("%lld%lld%lld",&n,&m,&p);
for(LL i=1; i<=n; i++)
{
scanf("%lld",&a[i]);
}
build(1,1,n);
for(LL i=1; i<=m; i++)
{
LL judge;
scanf("%lld",&judge);
if(judge==1)
{
LL x,y,z;
scanf("%lld%lld%lld",&x,&y,&z);
mul(1,x,y,z);
}
else if(judge==2)
{
LL x,y,z;
scanf("%lld%lld%lld",&x,&y,&z);
add(1,x,y,z);
}
else if(judge==3)
{
LL x,y;
scanf("%lld%lld",&x,&y);
printf("%lld\n",search(1,x,y));
}
}
}
总结:
时间仓促,细节不到。
记录学习,欢迎指正。