洛谷 PP3373 模板 線段樹 2

2021-07-30 18:03:39 字數 3616 閱讀 7029

題目大意:

已知乙個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;

endelse

begin

tree[p]:=(tree[p]+(r-l+1)*z) mod k;

cp[p]:=(cp[p]+z) mod k;

end;

endelse

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);

endelse

if s=3

then

begin

ans:=0;

read(x,y);

count(1,1,n,x,y);

writeln(ans);

end;

readln;

end;

end.

洛谷3373 線段樹2(線段樹)

rt,就是線段樹的模板,支援區間乘 區間加 區間求和。很有意思的一點是兩個標記的下傳,解決了就行了。然後這道題,作為ahoi,竟然是個裸的模板!可能年份久遠的原因吧。兩個一毛一樣嘛!includeusing namespace std typedef long long ll const ll ma...

洛谷P3373 模板 線段樹2

這題有毒啊,敲了我一晚上加一早上,總算a了。由於有加和乘兩個操作,要用2個lazy陣列。核心難點就是2個lazy陣列會相互影響。因為乘影響加,加不影響乘,所以我們先算乘。include include include include include include include include i...

洛谷 P3373 模板 線段樹 2

如題,已知乙個數列,你需要進行下面三種操作 1.將某區間每乙個數乘上x 2.將某區間每乙個數加上x 3.求出某區間每乙個數的和 第一行包含三個整數n m p,分別表示該數列數字的個數 操作的總個數和模數。第二行包含n個用空格分隔的整數,其中第i個數字表示數列第i項的初始值。接下來m行每行包含3或4個...