題目大意:
已知乙個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個...