P3373 【模板】线段树 2
一道板子题,思路和一基本没什么区别只是操作变了。话不多说上代码。
注意一下:这是大佬交给我们的指针写法,虽然不好理解但是比数组简洁方便容易错
声明:代码和HwH的线段树一样,因为是他帮我修改的。
#include<cstdio> const int maxn=100005; int p; typedef long long int ll; int n,q,m; ll a[maxn]; struct Node { ll tag1,tag2,v; int l,r; Node *ls,*rs; inline void maketag1(const ll w,const ll x) { v+=(r-l+1)%p*w%p; tag1=(tag1*x+w)%p; } inline void maketag2(const ll w) { v=v%p*w%p; tag2=tag2*w%p; } inline void pushup() { v=ls->v+rs->v; v%=p; } inline void pushdown() { if(tag1==0&&tag2==1) return; ls->maketag2(tag2); ls->maketag1(tag1,tag2); rs->maketag2(tag2); rs->maketag1(tag1,tag2); tag2=1,tag1=0; } Node(const int L,const int R) { l=L;r=R; if(l==r) { tag1=0; tag2=1; v=a[l]%p; ls=rs=NULL; } else { tag1=0; tag2=1; ll M=(L+R)>>1; ls=new Node(L,M); rs=new Node(M+1,R); pushup(); } } inline bool InRange(const int L,const int R) {return (L<=l)&&(r<=R);} inline bool OutofRange(const int L,const int R) {return (l>R)||(r<L);} void upd1(const ll L,const ll R,const ll w) { if(InRange(L,R)) { maketag1(w,1); return; } else if(!OutofRange(L,R)) { pushdown(); ls->upd1(L,R,w); rs->upd1(L,R,w); pushup(); } } ll qry(const int L,const int R) { if(InRange(L,R)) return v%p; if(OutofRange(L,R)) return 0; pushdown(); return (ls->qry(L,R)+rs->qry(L,R))%p; } void upd2(const int L,const int R,const ll w) { if(InRange(L,R)) { maketag1(0,w); maketag2(w); return; } else if(!OutofRange(L,R)) { pushdown(); ls->upd2(L,R,w); rs->upd2(L,R,w); pushup(); } } }; int main() { scanf("%d%d%d",&n,&q,&p); for(int i=1;i<=n;++i) scanf("%lld",a+i); Node *rot=new Node(1,n); for(ll o,x,y,z;q;--q) { scanf("%lld%lld%lld",&o,&x,&y); if(o==1) { scanf("%lld",&z); rot->upd2(x,y,z); } else if(o==2) { scanf("%lld",&z); rot->upd1(x,y,z); } else { printf("%lld\n",rot->qry(x,y)); } } return 0; }