bzoj1789 AHOI 維護數列(線段樹)

2022-05-12 13:38:53 字數 3835 閱讀 7840

首先想到線段樹,然後剛開始寫忽然想到樹狀陣列求和豈不是更快,而且程式設計複雜度又小,於是把之前寫的刪掉,寫樹狀陣列,寫完模版之後忽然發現這題竟然是區間修改!

於是又刪掉重寫,忽然發現不會處理又加又乘的,果斷看題解……

經過幾乎兩個小時的除錯,終於1a。

需要注意的是,一定要讓線段樹的每乙個區間儲存的值時刻為正確的,這樣才能在呼叫時直接返回。比如說這道題的change和query操作的最後一句話:

sum:=f(g[k<<1]+g[k<<1+1])

而不是sum:=f(t[k<<1].sum+t[k<<1+1].sum)

時刻記住這點就ok了。一開始我還以為我的模版記錯了呢……

**:

1

type node=record

2l,r,ti,ad,sum:int64;

3end;4

vari,n,m,tagtime,tagadd,ch,x,y,c,p:longint;

5 t:array[0..650000] of

node;

6function

f(x:int64):int64;

7begin

8 f:=x modp;9

end;

10function

g(k:longint):longint;

11begin

12with t[k] do

13begin

14 g:=f(f(sum*ti)+f(ad*(r-l+1

)));

15end;16

end;

17procedure

build(x,y,k:longint);

18var

mid:longint;

19begin

20with t[k] do

21begin

22 l:=x;r:=y;ad:=0;ti:=1;23

if l=r then

begin read(sum);sum:=f(sum);exit;end

;24 mid:=(l+r)>>1

;25 build(l,mid,k<<1

);26 build(mid+1,r,k<<1+1

);27 sum:=f(t[k<<1].sum+t[k<<1+1

].sum);

28end;29

end;

30procedure

pushdown(k:longint);

31begin

32with t[k] do

33begin

34if ti<>1

then

35begin

36 sum:=f(sum*ti);

37 t[k<<1].ti:=f(t[k<<1].ti*ti);

38 t[k<<1].ad:=f(t[k<<1].ad*ti);

39 t[k<<1+1].ti:=f(t[k<<1+1].ti*ti);

40 t[k<<1+1].ad:=f(t[k<<1+1].ad*ti);

41 ti:=1;42

end;

43if ad<>0

then

44begin

45 sum:=f(sum+ad*(r-l+1

));46 t[k<<1].ad:=f(t[k<<1].ad+ad);

47 t[k<<1+1].ad:=f(t[k<<1+1].ad+ad);

48 ad:=0;49

end;

50end;51

end;

52procedure

change(x,y,k:longint);

53var

mid:longint;

54begin

55with t[k] do

56begin

57if (l=x) and (r=y) then

58begin

59 ti:=(ti*tagtime) mod

p;60 ad:=(ad*tagtime+tagadd) mod

p;61

exit;

62end;63

pushdown(k);

64 mid:=(l+r)>>1;65

if y<=mid then change(x,y,k<<1)66

else

if x>mid then change(x,y,k<<1+1)67

else

68begin

69 change(x,mid,k<<1

);70 change(mid+1,y,k<<1+1

);71

end;

72 sum:=f(g(k<<1)+g(k<<1+1

));73

end;

74end;75

function

query(x,y,k:longint):longint;

76var

mid:longint;

77begin

78with t[k] do

79begin

80pushdown(k);

81if (l=x) and (r=y) then

exit(f(sum));

82 mid:=(l+r)>>1;83

if y<=mid then query:=f(query(x,y,k<<1

))84

else

if x>mid then query:=f(query(x,y,k<<1+1

))85

else query:=f(f(query(x,mid,k<<1))+f(query(mid+1,y,k<<1+1

)));

86 sum:=f(g(k<<1)+g(k<<1+1

));87

end;

88end;89

procedure

init;

90begin

91readln(n,p);

92 build(1,n,1

);93

end;

94procedure

main;

95begin

96readln(m);

97for i:=1

to m do

98begin

99read(ch);

100if ch=1

then

101begin

102readln(x,y,tagtime);

103 tagadd:=0

;104 change(x,y,1

);105

end106

else

if ch=2

then

107begin

108readln(x,y,tagadd);

109 tagtime:=1

;110 change(x,y,1

);111

end112

else

113begin

114readln(x,y);

115 writeln(query(x,y,1

));116

end;

117end

;118

end;

119begin

120init;

121main;

122end.

view code

雖然現在已經12:30了,但我感覺,很開心。做了這道題,值!

線段樹 AHOI 2009 維護序列

老師交給小可可乙個維護數列的任務,現在小可可希望你來幫他完成。有長為n的數列,不妨設為a1,a2,an 有如下三種操作形式 1 把數列中的一段數全部乘乙個值 2 把數列中的一段數全部加乙個值 3 詢問數列中的一段數的和,由於答案可能很大,你只需輸出這個數模p的值。第一行兩個整數n和p 1 p 100...

AHOI2009 維護序列 線段樹

老師交給小可可乙個維護數列的任務,現在小可可希望你來幫他完成。有長為n的數列,不妨設為a1,a2,an 有如下三種操作形式 1 把數列中的一段數全部乘乙個值 2 把數列中的一段數全部加乙個值 3 詢問數列中的一段數的和,由於答案可能很大,你只需輸出這個數模p的值。線段樹,打個乘法lazy標記即可 i...

bzoj1798 ahoi2009 維護序列

time limit 30 sec memory limit 64 mb submit 3714 solved 1364 submit status discuss 老師交給小可可乙個維護數列的任務,現在小可可希望你來幫他完成。有長為n的數列,不妨設為a1,a2,an 有如下三種操作形式 1 把數列...