洛谷 PP3373【模板】线段树 2

来源:互联网 发布:新手程序员 私活 编辑:程序博客网 时间:2024/06/07 18:43

题目大意:
已知一个N长数列,有M次操作,每次操作有3种:
s=1 将某区间[l,r]每一个数加上x
s=2 将某区间[l,r]每一个数乘上x
s=3 求出某区间[l,r]的总和 mod k。

对于30%的数据:N<=8,M<=10
对于70%的数据:N<=1000,M<=10000
对于100%的数据:N<=100000,M<=100000
(数据已经过加强^_^)

题解:
就是一个线段树+双重lazy的模版:
不过lazy操作要做双重的。
顺序,区间和*乘法lazy+加法lazy
当前区间如果下放乘法lazy,那么他儿子的2个lazy就都要乘上这个lazy,就等于(加法lazy+区间和乘法lazy) 这个乘法lazy,变成分开乘。加法lazy就只需要下传给儿子的加法lazy就可以了。

var     cp,rp,tree:array [0..1000001] of int64;     sum:array [0..1000001] of int64;     i,j,l,n,m,s,x,y:longint;     ans,k,z:int64;procedure build(p,l,r:longint);var      mid:longint;begin      mid:=(l+r) div 2;      tree[p]:=(sum[r]-sum[l-1]+k) mod k;      rp[p]:=1;      if l>=r then exit;      build(p*2,l,mid);      build(p*2+1,mid+1,r);end;procedure insert(p,l,r,a,b:longint);var      mid,i:longint;begin      mid:=(l+r) div 2;       if (l=a) and (r=b)          then begin                     tree[p * 2]:=(tree[p * 2]*rp[p]+(mid-l+1)*cp[p]) mod k;                     tree[p*2+1]:=(tree[p*2+1]*rp[p]+(r - mid)*cp[p]) mod k;                     rp[p * 2]:=rp[p * 2]*rp[p] mod k;                     rp[p*2+1]:=rp[p*2+1]*rp[p] mod k;                     cp[p * 2]:=(cp[p * 2]*rp[p]+cp[p]) mod k;                     cp[p*2+1]:=(cp[p*2+1]*rp[p]+cp[p]) mod k;                     cp[p]:=0;                     rp[p]:=1;                      if s=1 then                         begin                              tree[p]:=tree[p]*z mod k;                              rp[p]:=rp[p]*z mod k;                         end                         else begin                                   tree[p]:=(tree[p]+(r-l+1)*z) mod k;                                   cp[p]:=(cp[p]+z) mod k;                              end;               end          else begin                     tree[p * 2]:=(tree[p * 2]*rp[p]+(mid-l+1)*cp[p]) mod k;                     tree[p*2+1]:=(tree[p*2+1]*rp[p]+(r - mid)*cp[p]) mod k;                     rp[p * 2]:=rp[p * 2]*rp[p] mod k;                     rp[p*2+1]:=rp[p*2+1]*rp[p] mod k;                     cp[p * 2]:=(cp[p * 2]*rp[p]+cp[p]) mod k;                     cp[p*2+1]:=(cp[p*2+1]*rp[p]+cp[p]) mod k;                     cp[p]:=0;                     rp[p]:=1;                     if b<=mid then insert(p * 2,l,mid,a,b)                               else if a>mid then insert(p*2+1,mid+1,r,a,b)                                             else begin                                                         insert(p * 2,l,mid,a,mid);                                                         insert(p*2+1,mid+1,r,mid+1,b);                                                  end;                     tree[p]:=(tree[p * 2]+tree[p*2+1]) mod k;               end;end;procedure count(p,l,r,a,b:longint);var       mid,i:longint;begin       mid:=(l+r) div 2;       if (l=a) and (r=b)          then ans:=(ans+tree[p]) mod k          else begin                     tree[p * 2]:=(tree[p * 2]*rp[p]+(mid-l+1)*cp[p]) mod k;                     tree[p*2+1]:=(tree[p*2+1]*rp[p]+(r - mid)*cp[p]) mod k;                     rp[p * 2]:=rp[p * 2]*rp[p] mod k;                     rp[p*2+1]:=rp[p*2+1]*rp[p] mod k;                     cp[p * 2]:=(cp[p * 2]*rp[p]+cp[p]) mod k;                     cp[p*2+1]:=(cp[p*2+1]*rp[p]+cp[p]) mod k;                     cp[p]:=0;                     rp[p]:=1;                     if b<=mid then count(p * 2,l,mid,a,b)                               else if a>mid then count(p*2+1,mid+1,r,a,b)                                             else begin                                                         count(p * 2,l,mid,a,mid);                                                         count(p*2+1,mid+1,r,mid+1,b);                                                  end;               end;end;begin     readln(n,m,k);     for i:=1 to n do         begin              read(sum[i]);              sum[i]:=(sum[i]+sum[i-1]) mod k;         end;     build(1,1,n);     for i:=1 to m do         begin              read(s);              if (s=1) or (s=2) then                 begin                     read(x,y,z);                     insert(1,1,n,x,y);                 end              else if s=3 then                      begin                           ans:=0;                           read(x,y);                           count(1,1,n,x,y);                           writeln(ans);                      end;              readln;         end;end.
1 0