双标记线段树
因为乘除有优先级关系,所以每访问到一个节点就把这个节点的标记往下传。
pushdown中退出的条件是该点为叶子节点(p*2+1>tot)
但是要注意tot的计算,是在build中节点编号最大的那个为tot(因此WA了好几次。。)
program seq; type point=record l,r,sum,mul,add:int64;//tag end; var tree:array[1..400000]of point; i:longint; n,pp,m,tot,cz,t,g,c:int64; a:array[1..100000]of int64; procedure resum(p:int64); begin tree[p].sum:=(tree[p*2].sum+tree[p*2+1].sum) mod pp; end; procedure pushdown(p:int64); begin if p*2+1>tot then //是>tot,不是>n。二叉树节点个数不止n begin tree[p].mul:=1; tree[p].add:=0; exit; end; tree[p*2].sum:=(tree[p*2].sum*tree[p].mul mod pp+tree[p].add*(tree[p*2].r-tree[p*2].l+1) mod pp) mod pp; tree[p*2+1].sum:=(tree[p*2+1].sum*tree[p].mul mod pp+tree[p].add*(tree[p*2+1].r-tree[p*2+1].l+1) mod pp) mod pp; tree[p*2].mul:=(tree[p*2].mul*tree[p].mul) mod pp; tree[p*2+1].mul:=(tree[p*2+1].mul*tree[p].mul) mod pp; tree[p*2].add:=(tree[p*2].add*tree[p].mul mod pp+tree[p].add) mod pp; tree[p*2+1].add:=(tree[p*2+1].add*tree[p].mul mod pp+tree[p].add) mod pp; tree[p].mul:=1; tree[p].add:=0; end; procedure build(p,l,r:int64); var mid:int64; begin if p>tot then tot:=p;//!!!! tree[p].l:=l; tree[p].r:=r; tree[p].mul:=1; tree[p].add:=0; if l=r then begin tree[p].sum:=a[l] mod pp; exit; end; mid:=(l+r) div 2; build(p*2,l,mid); build(p*2+1,mid+1,r); resum(p); end; procedure change(p,l,r,c,g:int64); var mid:int64; begin if (tree[p].l=l)and(tree[p].r=r) then begin tree[p].mul:=tree[p].mul*c mod pp; tree[p].add:=(tree[p].add*c mod pp+g) mod pp; tree[p].sum:=(tree[p].sum*c mod pp+g*(tree[p].r-tree[p].l+1) mod pp) mod pp; exit; end; pushdown(p); mid:=(tree[p].l+tree[p].r) div 2; if r<=mid then change(p*2,l,r,c,g); if l>mid then change(p*2+1,l,r,c,g); if (l<=mid)and(r>mid) then begin change(p*2,l,mid,c,g); change(p*2+1,mid+1,r,c,g); end; resum(p); end; function find(p,l,r:int64):int64; var mid:int64; s1,s2:int64; begin if (tree[p].l=l)and(tree[p].r=r) then begin find:=tree[p].sum; exit; end; pushdown(p); mid:=(tree[p].l+tree[p].r) div 2; if r<=mid then exit(find(p*2,l,r)); if l>mid then exit(find(p*2+1,l,r)); if (l<=mid)and(r>mid) then begin s1:=find(p*2,l,mid); s2:=find(p*2+1,mid+1,r); exit((s1+s2) mod pp); end; end; { procedure dfs(p:longint); begin writeln('[',tree[p].l,',',tree[p].r,']:',tree[p].sum,' ',tree[p].add,' ',tree[p].mul); if tree[p].l=tree[p].r then exit; dfs(p*2); dfs(p*2+1); end;} begin read(n,pp); for i:=1 to n do read(a[i]); build(1,1,n); read(m); for i:=1 to m do begin read(cz,t,g); if cz=1 then begin read(c); change(1,t,g,c,0);//*c+0 end; if cz=2 then begin read(c); change(1,t,g,1,c);//*1+c; end; if cz=3 then writeln(find(1,t,g) mod pp); end; end.