第二次做 线段树2 了,之前研究了两节晚自习自以为完全理解了,但是今天写还是有一点小差错,值得反思。
稍微总结下线段树2的要点。
<1> 乘法标记影响加法标记,更新 乘法标记 时应将对应的 加法标记 乘上 乘法标记乘的值(key)
<2> 标记下传中 乘法标记 应优先于 加法标记,由于我们在更新 乘法标记 时更新了 加法标记,所以如果乘法不优先的话,先乘再加的操作会出现误差
<3> 加或乘的操作中每一层算完儿子节点后都应更新当前节点信息,查询则不需要,更新操作只在 子区间 和 其子区间(down) 中进行,所以父区间都应由儿子更新
<4> memset有毒,害我找了40+分钟错误,我一开始用memset将乘法标记设为1,但样例怎么样都过不了,还是看了之前自己的题解,改成 建树过程中将标记设为1 才AC的
下面是我的代码(以前代码是真的丑)
#include <bits/stdc++.h>
using namespace std;
long long a[100005],he[800005],lazy[800005],hard[800005];
int ll,rr,n,m;
long long ans,P;
void biu(int t,int l,int r)
{
hard[t]=1;//memset有毒,别用
if(l==r)
{
he[t]=a[l]%P;
return;
}
int mid=l+r>>1;
biu(2*t,l,mid);
biu(2*t+1,mid+1,r);
he[t]=(he[2*t]+he[2*t+1])%P;
return;
}
void down(int t,int l,int r)//标记下传
{
if(lazy[t]==0&&hard[t]==1) return;
//乘法优先:乘标记影响加标记
lazy[2*t]=(lazy[2*t]*hard[t])%P;
lazy[2*t+1]=(lazy[2*t+1]*hard[t])%P;
hard[2*t]=(hard[2*t]*hard[t])%P;
hard[2*t+1]=(hard[2*t+1]*hard[t])%P;
lazy[2*t]=(lazy[2*t]+lazy[t])%P;
lazy[2*t+1]=(lazy[2*t+1]+lazy[t])%P;
int mid=l+r>>1;
he[2*t]=(((he[2*t]*hard[t])%P)+((lazy[t]*(mid-l+1))%P))%P;
he[2*t+1]=(((he[2*t+1]*hard[t])%P)+((lazy[t]*(r-mid))%P))%P;
hard[t]=1;
lazy[t]=0;
}
void ask(int t,int l,int r)
{
if(ll<=l&&r<=rr)
{
ans=(ans+he[t])%P;
return;
}
down(t,l,r);
int mid=l+r>>1;
if(ll<=mid) ask(2*t,l,mid);
if(rr> mid) ask(2*t+1,mid+1,r);
//he[t]=(he[2*t]+he[2*t+1])%P; 没更新 ,不用加
return;
}
void jia(int t,int l,int r,long long key)
{
if(ll<=l&&r<=rr)
{
he[t]=(he[t]+((r-l+1)*key%P))%P;
lazy[t]=(lazy[t]+key)%P;
return;
}
int mid=l+r>>1;
down(t,l,r);
if(ll<=mid) jia(2*t,l,mid,key);
if(rr> mid) jia(2*t+1,mid+1,r,key);
he[t]=(he[2*t]+he[2*t+1])%P;
return;
}
void cheng(int t,int l,int r,long long key)
{
if(ll<=l&&r<=rr)
{
he[t]=(he[t]*key)%P;
hard[t]=(hard[t]*key)%P;
lazy[t]=(lazy[t]*key)%P;
//printf("Edge %d sum=%lld\n",t,he[t]);
return;
}
int mid=l+r>>1;
down(t,l,r);
if(ll<=mid) cheng(2*t,l,mid,key);
if(rr> mid) cheng(2*t+1,mid+1,r,key);
he[t]=(he[2*t]+he[2*t+1])%P;
return;
}
int main()
{
scanf("%d%d%lld",&n,&m,&P);
int x;long long k;
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
//memset(hard,1,sizeof(hard));
biu(1,1,n);
for(int i=1;i<=m;i++)
{
scanf("%d",&x);
if(x==1){scanf("%d%d%lld",&ll,&rr,&k);cheng(1,1,n,k);}
if(x==2){scanf("%d%d%lld",&ll,&rr,&k); jia(1,1,n,k);}
if(x==3){scanf("%d%d",&ll,&rr);ask(1,1,n);printf("%lld\n",ans);ans=0;}
}
return 0;
}
来源:https://www.cnblogs.com/Miniweasel/p/9893588.html