CodeVS 4927-线段树练习5

原题

题目描述 Description

有n个数和5种操作:

add a b c:把区间[a,b]内的所有数都增加c;

set a b c:把区间[a,b]内的所有数都设为c;

sum a b:查询区间[a,b]的区间和;

max a b:查询区间[a,b]的最大值;

min a b:查询区间[a,b]的最小值.

输入描述 Input Description

第一行两个整数n,m,第二行n个整数表示这n个数的初始值.

接下来m行操作,同题目描述.

输出描述 Output Description

对于所有的sum、max、min询问,一行输出一个答案

样例输入 Sample Input

10 6

3 9 2 8 1 7 5 0 4 6

add 4 9 4

set 2 6 2

add 3 8 2

sum 2 10

max 1 7

min 3 6

样例输出 Sample Output

49

11

4

数据范围及提示 Data Size & Hint

10%:1<n,m<=10

30%:1<n,m<=10000

100%:1<n,m<=100000

保证中间结果在long long(C/C++)、int64(pascal)范围内

 

题解

思路不难,可是码农题调起来就是变态,一搞就是一两天...毕竟这是一棵功能完备的线段树.

这题最难的就是add和set两个Lazy标记.

要先明确一点,就是set的Lazy优先级大于add的Lazy,因为不管你前面的操作再多,一个set下去也必须全部清除.

因此:在标记set的Lazy的时候,就要把add的Lazy清除,并更新该节点的set值;在标记add的Lazy的时候,就要判断一下,如果改点已经是set过了的,就要将set加上要add的数,并把改点的add Lazy清零.

在标记set或add的过程中,在子程序的最前端一定要有一个判断,如果路上的搜索到的点所表示的区间已经被set过了,那么一定要先将该点的set下传,并更新该点的sum/max/min值.如果该点没被set过且不是目标区间且del不为0,那么将该点的del下传,并更新该点的sum/max/min值.还有一点很重要,就是一个节点不可能同时存在set的Lazy与add的Lazy.

查询sum/max/min的时候,在子程序的最前端依旧要有一个判断,如果该点所表示的区间已经被set过了,那么一定要先将该点的set下传,并更新该点的sum/max/min值.

这题子程序贼多...但如果没有的话,在下传set或add时就会特别混乱=_=.

下面是代码:

 

uses math;
var sum,st,del,mx,mn:array[1..800000] of int64;
var a:array[1..100000] of int64; 
var en:array[1..800000] of boolean;
var n,m,x,y,z:int64;
var c1,c2,c3,c4:char;
var j,i:longint;
function calcsum(h,l,r:int64):int64;
var m,p:int64;
begin
  m:=(l+r)>>1;
  if en[h<<1] then p:=st[h<<1]*(m-l+1) else p:=sum[h<<1]+del[h<<1]*(m-l+1);
  if en[h<<1+1] then inc(p,st[h<<1+1]*(r-m)) else inc(p,sum[h<<1+1]+del[h<<1+1]*(r-m));
  exit(p);
end;
function calcmax(h,l,r:int64):int64;
var p:int64;
begin
  if en[h<<1] then p:=st[h<<1] else p:=mx[h<<1]+del[h<<1];
  if en[h<<1+1] then p:=max(p,st[h<<1+1]) else p:=max(p,mx[h<<1+1]+del[h<<1+1]);
  exit(p);
end;
function calcmin(h,l,r:int64):int64;
var p:int64;
begin
  if en[h<<1] then p:=st[h<<1] else p:=mn[h<<1]+del[h<<1];
  if en[h<<1+1] then p:=min(p,st[h<<1+1]) else p:=min(p,mn[h<<1+1]+del[h<<1+1]);
  exit(p);
end;
procedure build(h,l,r:int64);
var m:int64;
begin
  if l=r then begin sum[h]:=a[l];mx[h]:=a[l];mn[h]:=a[l];exit; end;
  m:=(l+r)>>1;
  build(h<<1,l,m);build(h<<1+1,m+1,r);
  sum[h]:=sum[h<<1]+sum[h<<1+1];
  mx[h]:=max(mx[h<<1],mx[h<<1+1]);
  mn[h]:=min(mn[h<<1],mn[h<<1+1]);
end;
procedure downset(h,l,r:int64);
begin
  st[h<<1]:=st[h];st[h<<1+1]:=st[h];
  en[h<<1]:=true;en[h<<1+1]:=true;en[h]:=false;
  del[h<<1]:=0;del[h<<1+1]:=0;
  mx[h]:=st[h];mn[h]:=st[h];sum[h]:=st[h]*(r-l+1);
end;
procedure downdel(h,l,r:int64);
begin
  if en[h<<1] then inc(st[h<<1],del[h]) else del[h<<1]:=del[h<<1]+del[h];
  if en[h<<1+1] then inc(st[h<<1+1],del[h]) else del[h<<1+1]:=del[h<<1+1]+del[h];
  inc(mx[h],del[h]);inc(mn[h],del[h]);inc(sum[h],del[h]*(r-l+1));
  del[h]:=0;
end;
procedure add(h,l,r,x,y,c:int64);
var m:int64;
begin
  if en[h] then downset(h,l,r);
  if (l>=x)and(r<=y) then
  begin
    del[h]:=del[h]+c;
    if en[h] then begin st[h]:=st[h]+c;del[h]:=0; end;
    exit;
  end;
  m:=(l+r)>>1;
  if del[h]>0 then downdel(h,l,r);
  if x<=m then add(h<<1,l,m,x,y,c);
  if y>m then add(h<<1+1,m+1,r,x,y,c);
  sum[h]:=calcsum(h,l,r);mx[h]:=calcmax(h,l,r);mn[h]:=calcmin(h,l,r);
end;
procedure setup(h,l,r,x,y,num:int64);
var m,p:int64;
begin
  if en[h] then downset(h,l,r);
  if (l>=x)and(r<=y) then
  begin
    st[h]:=num;en[h]:=true;
    del[h]:=0;exit;
  end;
  if del[h]>0 then downdel(h,l,r);
  m:=(l+r)>>1;
  if x<=m then setup(h<<1,l,m,x,y,num);
  if y>m then setup(h<<1+1,m+1,r,x,y,num);
  sum[h]:=calcsum(h,l,r);mx[h]:=calcmax(h,l,r);mn[h]:=calcmin(h,l,r);
end;
function asksum(h,l,r,x,y:int64):int64;
var m,p:int64;
begin
  if en[h] then downset(h,l,r);p:=0;
  if (l>=x)and(r<=y) then if en[h] then p:=p+st[h]*(r-l+1) else p:=p+sum[h]+del[h]*(r-l+1) else
  begin
    if del[h]>0 then downdel(h,l,r);
    m:=(l+r)>>1;
    if x<=m then p:=p+asksum(h<<1,l,m,x,y);
    if y>m then p:=p+asksum(h<<1+1,m+1,r,x,y);
  end;
  exit(p);
end;
function askmax(h,l,r,x,y:int64):int64;
var m,p:int64;
begin
  p:=-10000000;
  if en[h] then downset(h,l,r);
  if (l>=x)and(r<=y) then if en[h] then p:=max(p,st[h]) else p:=max(p,mx[h]+del[h]) else
  begin
    if del[h]>0 then downdel(h,l,r);
    m:=(l+r)>>1;
    if x<=m then p:=max(p,askmax(h<<1,l,m,x,y));
    if y>m then p:=max(p,askmax(h<<1+1,m+1,r,x,y));
  end;
  exit(p);
end;
function askmin(h,l,r,x,y:int64):int64;
var m,p:int64;
begin
  p:=10000000;
  if en[h] then downset(h,l,r);
  if (l>=x)and(r<=y) then if en[h] then p:=min(p,st[h]) else p:=min(p,mn[h]+del[h]) else
  begin
    if del[h]>0 then downdel(h,l,r);
    m:=(l+r)>>1;
    if x<=m then p:=min(p,askmin(h<<1,l,m,x,y));
    if y>m then p:=min(p,askmin(h<<1+1,m+1,r,x,y));
  end;
  exit(p);
end;
begin
  readln(n,m);
  for i:=1 to n do read(a[i]);readln;
  build(1,1,n);
  for i:=1 to m do
  begin
    read(c1,c2,c3,c4);
    if c2='e' then begin readln(x,y,z);setup(1,1,n,x,y,z); end;
    if c2='d' then begin readln(x,y,z);add(1,1,n,x,y,z); end;
    if c2='u' then begin readln(x,y);writeln(asksum(1,1,n,x,y)); end;
    if c2='a' then begin readln(x,y);writeln(askmax(1,1,n,x,y)); end;
    if c2='i' then begin readln(x,y);writeln(askmin(1,1,n,x,y)); end;
  end;
end.

 

posted @ 2017-03-07 13:16  ALHDLIOX  阅读(168)  评论(0编辑  收藏  举报