线段树模板
线段树其实复习的不是什么思想,主要应该是自己的代码风格与边界处理,就直接由题目来复习吧。另外,重新理解一下线段树的操作原理对于做题时很有帮助的。比赛前一定要耐心看一下每一种线段树的建树与维护方式。
pascal模板
不修改的RMQ:
例题:vijosP1514 天才的记忆
var x,y,i,j,k,l,m,n:longint; tree,a:array[0..1200000] of longint; function max(a,b:longint):longint; begin if a>b then exit(a); exit(b); end; {建树} procedure build_tree(l,r,num:longint); var mid:longint; begin if l=r then begin tree[num]:=a[l]; exit; end; mid:=(l+r)>>1; build_tree(l,mid,num<<1); build_tree(mid+1,r,num<<1+1); tree[num]:=max(tree[num<<1],tree[num<<1+1]); end; {求解区间极值} function query(l,r,num:longint):longint; var mid:longint; begin if (x<=l)and(y>=r) then exit(tree[num]); mid:=(l+r)>>1; if x>mid then exit(query(mid+1,r,num<<1+1)) else if y<=mid then exit(query(l,mid,num<<1)) else exit(max(query(l,mid,num<<1),query(mid+1,r,num<<1+1))); end; begin readln(n); for i:=1 to n do read(a[i]); readln; build_tree(1,n,1); readln(m); for i:=1 to m do begin readln(x,y); writeln(query(1,n,1)); end; end.
单点更新区间求和:
例题:hduP1166 敌兵布阵
var a:array[1..100100] of longint; tree:array[1..100100] of longint; i,j,n,m,t,x,y,u:longint; ch:char; {建树} procedure build_tree(l,r,num:longint); var mid:longint; begin if l=r then begin tree[num]:=a[l]; exit; end else begin mid:=(l+r) shr 1; build_tree(l,mid,num shl 1); build_tree(mid+1,r,num shl 1+1); tree[num]:=tree[num shl 1]+tree[num shl 1+1]; end; end; {单点修改} procedure add(l,r,num:longint); var mid:longint; begin if (l=r) then begin inc(tree[num],y); exit; end; mid:=(l+r)shr 1; if x<=mid then begin add(l,mid,num shl 1); inc(tree[num],y); end else begin add(mid+1,r,num shl 1+1); inc(tree[num],y); end; end; {区间求和} function sum(l,r,num:longint):longint; var mid:longint; begin if l=r then exit(tree[num]); mid:=(l+r)shr 1; if y<=mid then exit(sum(l,mid,num shl 1)) else if x>mid then exit(sum(mid+1,r,num shl 1+1)) else exit(sum(l,mid,num<<1)+sum(mid+1,r,num shl 1+1)); end; begin readln(t); for j:=1 to t do begin writeln('Case',j,':'); readln(n); for i:=1 to n do read(a[i]); readln; build_tree(1,n,1); read(ch); while ch<>'E' do begin if ch='Q' then begin for i:=2 to 5 do read(ch); read(x,y); writeln(sum(1,n,1)); end else if ch='A' then begin for i:=2 to 3 do read(ch); read(x,y); add(1,n,1); end else begin for i:=2 to 3 do read(ch); read(x,y); y:=-y; add(1,n,1); end; readln; read(ch); end; readln; end; end.
单点更新区间求极值:
例题:hduP1754 I hate it
var a,tree:array[1..1000000] of longint; n,m,l,r,x,y,t,u,i,j:longint; ch,ch1,ch2:char; function max(a,b:longint):longint; begin if a > b then max:=a else max:=b; end; {建树} procedure build_tree(l,r,num:longint); var mid:longint; begin if l=r then begin tree[num]:=a[l]; exit; end else begin mid:=(l+r) shr 1; build_tree(l,mid,num shl 1); build_tree(mid+1,r,num shl 1+1); if tree[num shl 1] > tree[num shl 1+1] then tree[num]:=tree[num shl 1] else tree[num]:=tree[num shl 1+1]; end; end; {单点修改} procedure change(l,r,num:longint); var mid:longint; begin if (l=r) then begin tree[num]:=y; exit; end; mid:=(l+r) shr 1; if x <= mid then begin change(l,mid,num shl 1); if tree[num shl 1] > tree[num shl 1+1] then tree[num]:=tree[num shl 1] else tree[num]:=tree[num shl 1+1]; end else begin change(mid+1,r,num shl 1+1); if tree[num shl 1] > tree[num shl 1+1] then tree[num]:=tree[num shl 1] else tree[num]:=tree[num shl 1+1]; end; end; {区间求极值} function query(l,r,num:longint):longint; var mid:longint; begin if (x <= l)and(y >= r) then query := tree[num] else begin mid:=(l+r) shr 1; if y <= mid then query:=query(l,mid,num shl 1) else if x > mid then query:=query(mid+1,r,num shl 1+1) else query:=max(query(l,mid,num shl 1),query(mid+1,r,num shl 1+1)); end; end; begin while not eof do begin readln(n,m); for i:=1 to n do read(a[i]); readln; build_tree(1,n,1); for i:=1 to m do begin readln(ch,x,y); if ch='Q' then writeln(query(1,n,1)); if ch='U' then change(1,n,1); end; end; end.
成端更新区间求极值
例题:vijosP1659 河蟹王国
var q,x,y,c,i,j,k,l,m,n:longint; mark,tree:array[1..600000] of longint; a:array[1..100000] of longint; function max(a,b:longint):longint; begin if a>b then exit(a); exit(b); end; {清除父节点的标记,将其加到父节点上,同时传递标记至子节点} procedure clean(num:longint); begin if mark[num]=0 then exit; inc(mark[num<<1],mark[num]); inc(mark[num<<1+1],mark[num]); inc(tree[num],mark[num]); mark[num]:=0; end; {建树} procedure build_tree(l,r,num:longint); var mid:longint; begin if l=r then begin tree[num]:=a[l]; exit; end else begin mid:=(l+r)>>1; build_tree(l,mid,num<<1); build_tree(mid+1,r,num<<1+1); tree[num]:=max(tree[num<<1],tree[num<<1+1]); end; end; {区间修改} procedure add(l,r,num:longint); var mid:longint; begin clean(num); if (x<=l) and (y>=r) then begin inc(mark[num],c); exit; end; mid:=(l+r)>>1; if x>mid then add(mid+1,r,num<<1+1) else if y<=mid then add(l,mid,num<<1) else begin add(l,mid,num<<1); add(mid+1,r,num<<1+1); end; clean(num<<1); clean(num<<1+1); tree[num]:=max(tree[num<<1],tree[num<<1+1]); end; {区间求极值} function query(l,r,num:longint):longint; var mid:longint; begin clean(num); if (x<=l)and(y>=r) then exit(tree[num]); mid:=(l+r)>>1; if y<=mid then exit(query(l,mid,num<<1)) else if x>mid then exit(query(mid+1,r,num<<1+1)) else exit(max(query(l,mid,num<<1),query(mid+1,r,num<<1+1))); end; begin readln(n); for i:=1 to n do readln(a[i]); build_tree(1,n,1); readln(m); for i:=1 to m do begin read(q); if q=1 then begin readln(x,y,c); add(1,n,1); end else begin readln(x,y); writeln(query(1,n,1)); end; end; end.
线段树+DP
例题:vijosP1083小白逛公园
var before,q,x,y,i,j,k,l,m,n:longint; mc,ma,mb,sum:array[1..3000000] of longint; tree:array[1..500001] of longint; function max(a,b:longint):longint; begin if a>b then exit(a); exit(b); end; {建树} procedure build_tree(l,r,num:longint); var mid:longint; begin if l=r then begin ma[num]:=tree[l]; mb[num]:=tree[l]; sum[num]:=tree[l]; mc[num]:=tree[l]; exit; end; mid:=(l+r)>>1; build_tree(l,mid,num<<1); build_tree(mid+1,r,num<<1+1); sum[num]:=sum[num<<1]+sum[num<<1+1]; ma[num]:=max(ma[num<<1],sum[num<<1]+ma[num<<1+1]); mb[num]:=max(mb[num<<1]+sum[num<<1+1],mb[num<<1+1]); mc[num]:=max(mc[num<<1],mc[num<<1+1]); mc[num]:=max(mc[num],mb[num<<1]+ma[num<<1+1]); end; {修改} procedure change(l,r,num:longint); var mid:longint; begin if l=r then begin ma[num]:=y; mb[num]:=y; sum[num]:=y; mc[num]:=y; exit; end; mid:=(l+r)>>1; if x<=mid then change(l,mid,num<<1) else change(mid+1,r,num<<1+1); sum[num]:=sum[num<<1]+sum[num<<1+1]; ma[num]:=max(ma[num<<1],sum[num<<1]+ma[num<<1+1]); mb[num]:=max(mb[num<<1]+sum[num<<1+1],mb[num<<1+1]); mc[num]:=max(mc[num<<1],mc[num<<1+1]); mc[num]:=max(mc[num],mb[num<<1]+ma[num<<1+1]); end; function query:longint; var mid:longint; procedure ask(l,r,num:longint); var mid:longint; begin if (x<=l)and(r<=y) then begin query:=max(query,ma[num]+before); query:=max(query,mc[num]); before:=max(mb[num],sum[num]+before); exit; end; mid:=(l+r)>>1; if y<=mid then ask(l,mid,num<<1) else if x>mid then ask(mid+1,r,num<<1+1) else begin ask(l,mid,num<<1); ask(mid+1,r,num<<1+1); end; end; begin before:=-100000; query:=-100000; ask(1,n,1); end; begin readln(n,m); for i:=1 to n do read(tree[i]); build_tree(1,n,1); readln; for i:=1 to m do begin readln(q,x,y); if q=1 then begin if x>y then begin q:=x; x:=y; y:=q; end; writeln(query); end else change(1,n,1); end; end.
愿你出走半生,归来仍是少年