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

原创 2016年06月01日 20:17:29

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


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

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

一开始的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.


版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

hdu 4893 线段树 --- 也是两个变 类似双标记

http://acm.hdu.edu.cn/showproblem.php?pid=4893 开始的时候,我按双标记,WA了一下午,搞不定,我是用的两个标记add--表示当前结点中有值发生变...

[bzoj4033]树上染色

题目描述有一棵点数为N的树,树边有边权。给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并 将其他的N-K个点染成白色。将所有点染色后,你会获得黑点两两之间的距离加上白点两两...

bzoj 1798 AHOI 2009 Seq 维护序列 [线段树]

1798: [Ahoi2009]Seq 维护序列seqTime Limit: 30 Sec Memory Limit: 64 MB Submit: 5229 Solved: 1861Descri...

AHOI 2009 (BZOJ1798)维护序列 seq (线段树好题?)

我是不会说这个题很坑的。。 改了一晚上。。。 // by SiriusRen #include #define N 150000 #define LSON l,mid,lson #define ...

【BZOJ1798】【Ahoi2009】维护序列seq(线段树)

Description老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。 有长为N的数列,不妨设为a1,a2,…,aN 。有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)...

BZOJ1798:[Ahoi2009]Seq 维护序列 线段树

题目大意:维护一个序列,支持3种操作 1.区间上每一个点的值乘一个数 2.区间上每一个点的值加一个数 3.查询一段区间的数值之和 线段树裸题 注意:传乘法标记的时候,初始值要设成1 ...
  • Oakley_
  • Oakley_
  • 2016年07月27日 17:09
  • 621

BZOJ 1798 AHOI2009 Seq 维护序列 线段树

题目大意:维护一个序列,提供三种操作: 1.将区间中每一个点的权值乘上一个数 2.将区间中每一个点的权值加上一个数 3.求一段区间的和对p取模的值 2631的超^n级弱化版,写2631之前可以...
  • PoPoQQQ
  • PoPoQQQ
  • 2014年09月28日 12:57
  • 1452

【BZOJ1798】[Ahoi2009]Seq 维护序列seq 线段树

简单的线段树+lazy标记下传。 维护加法和乘法两个标记。注意当标记下传时要先乘后加。 写代码时稍稍注意一点点就不会有大问题。...
  • eolv99
  • eolv99
  • 2014年12月03日 11:08
  • 446

Bzoj 1798: [Ahoi2009]Seq 维护序列seq(线段树区间操作)

1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec Memory Limit: 64 MB Description 老师交给小可可一个维护...

bzoj 1798: [Ahoi2009]Seq 维护序列seq 线段树 区间乘法区间加法 区间求和

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1798题意:题解:线段树,区间乘法+区间加法,都扔给一个updata就好代码:#includ...
  • yxg_123
  • yxg_123
  • 2017年03月02日 16:43
  • 244
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:bzoj 1798: [Ahoi2009]Seq 维护序列seq 双标记线段树
举报原因:
原因补充:

(最多只允许输入30个字)