bzoj1798 AHOI2009seq

双标记线段树

因为乘除有优先级关系,所以每访问到一个节点就把这个节点的标记往下传。

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.


你可能感兴趣的:(数据结构,tag,lazy,bzoj)