第二次做 线段树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