beginend

只要在路上,就没有到不了的远方

bzoj 1798: [Ahoi2009]Seq 维护序列seq 双标记线段树

题意:给出一个序列,有三个操作:每一段加上一个数或乘上一个数或输出这一段的和。


分析:一开始想不就是傻叉线段树吗,后来才发现没那么简单。

不过也只要维护一下运算顺序就好了。

一开始的pushlazy函数写的不优美,然后不知道为什么不停地WA,至今仍然没有找到原因。

后来看了别人的程序,把push操作改写了一下,也就是每个lazy标记都是已经被当前区间处理过的了,每一次push只要更改子区间的sum和lazy就好了。

看来代码风格优美一点还是很重要的!!!


代码:

const
  maxn=101000;
 
var
  t:array[1..maxn*10] of record
    l,r:longint;
    s,lazy1,lazy2:int64;
  end;
  n,tot:longint;
  p:int64;
  s:array[0..maxn] of int64;
 
procedure build(d,l,r:longint);
var
  m:longint;
begin
  if d>tot then tot:=d;
  t[d].l:=l;
  t[d].r:=r;
  t[d].s:=(s[r]-s[l-1]+p) mod p;
  t[d].lazy1:=1;
  t[d].lazy2:=0;
  if l=r then exit;
  m:=(l+r) div 2;
  build(d*2,l,m);
  build(d*2+1,m+1,r);
end;
 
procedure init;
var
  i:longint;
begin
  readln(n,p);
  for i:=1 to n do
  begin
    read(s[i]);
    s[i]:=(s[i-1]+s[i]) mod p;
  end;
  readln;
  build(1,1,n);
end;
 
procedure pushlazy(d:longint);
var
  x:longint;
begin
  if t[d].l=t[d].r then
  begin
    t[d].lazy1:=1;
    t[d].lazy2:=0;
    exit;
  end;
  t[d*2].s:=(t[d*2].s*t[d].lazy1+t[d].lazy2*(t[d*2].r-t[d*2].l+1)) mod p;
  t[d*2+1].s:=(t[d*2+1].s*t[d].lazy1+t[d].lazy2*(t[d*2+1].r-t[d*2+1].l+1)) mod p;
  t[d*2].lazy1:=t[d*2].lazy1*t[d].lazy1 mod p;
  t[d*2].lazy2:=(t[d*2].lazy2*t[d].lazy1+t[d].lazy2) mod p;
  t[d*2+1].lazy1:=t[d*2+1].lazy1*t[d].lazy1 mod p;
  t[d*2+1].lazy2:=(t[d*2+1].lazy2*t[d].lazy1+t[d].lazy2) mod p;
  t[d].lazy1:=1;
  t[d].lazy2:=0;
end;
 
procedure insert(d,l,r,k:longint;w:int64);
var
  m:longint;
begin
  pushlazy(d);
  if (t[d].l=l)and(t[d].r=r) then
  begin
    if k=1
      then begin
             t[d].s:=t[d].s*w mod p;
             t[d].lazy1:=t[d].lazy1*w mod p;
           end
      else begin
             t[d].s:=(t[d].s+(t[d].r-t[d].l+1)*w) mod p;
             t[d].lazy2:=(t[d].lazy2+w) mod p;
           end;
    exit;
  end;
  m:=(t[d].l+t[d].r) div 2;
  if r<=m
    then insert(d*2,l,r,k,w)
    else if l>m
           then insert(d*2+1,l,r,k,w)
           else begin
                  insert(d*2,l,m,k,w);
                  insert(d*2+1,m+1,r,k,w);
                end;
  t[d].s:=(t[d*2].s+t[d*2+1].s) mod p;
end;
 
function find(d,l,r:longint):int64;
var
  m:longint;
begin
  pushlazy(d);
  if (t[d].l=l)and(t[d].r=r) then exit(t[d].s mod p);
  m:=(t[d].l+t[d].r) div 2;
  if r<=m
    then exit(find(d*2,l,r))
    else if l>m
           then exit(find(d*2+1,l,r))
           else exit((find(d*2,l,m)+find(d*2+1,m+1,r)) mod p);
end;
 
procedure main;
var
  q,i,x,y,z,j:longint;
begin
  readln(q);
  for i:=1 to q do
  begin
    read(x);
    if x=1
      then begin
             readln(x,y,z);
             insert(1,x,y,1,z);
           end
      else if x=2
             then begin
                    readln(x,y,z);
                    insert(1,x,y,2,z);
                  end
             else begin
                    readln(x,y);
                    writeln(find(1,x,y));
                  end;
  end;
end;
 
begin
  init;
  main;
end.


阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_33229466/article/details/51558644
个人分类: 线段树
上一篇bzoj 1503: [NOI2004]郁闷的出纳员 treap
下一篇bzoj 1057: [ZJOI2007]棋盘制作 求最大全0/1矩阵(极大扩展矩阵)动态规划
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭