題目大意:有一個二分圖,對於左邊的第i個點,權值爲a[i],右邊的第i個點權值b[i]。現圖中有m條邊,第i條邊連接s[i],t[i]兩點,權值爲a[s[i]]+b[s[i]],選擇其中若干條邊,使總權值最大,但是選出來的邊兩兩不相交。
這道題近似於codevs上的線段覆蓋,於是在實現上我們也用上一個近似於線段覆蓋的方法來完成這道題(好扯淡……):
1. 讀入全部數據
2. 將所有的邊以起點爲第一關鍵字(升序),終點爲第二關鍵字(降序)進行排序
3. DP,f[i]表示在右邊前i個點(包括i)的最大權值,那麼我們有
f[t[i]]= max(f[t[i]],a[s[i]]+b[t[i]]) (t[i]=1)
max(f[t[i]],max{f[t[i]-1]}+a[s[i]]+b[t[i]]) (t[i]>1)
那麼,麻煩就麻煩在不能直接把前t[i]-1個點裏面的最大f值用打擂臺的方式找出來,那麼怎麼辦呢?用線段樹進行優化。在第3步裏面,先把後面的公式的值用k存起來,如果k>f[t[i]],那麼f[t[i]]=k再把f[t[i]]存入線段樹中。這樣一來,我們在求t[i]>1的k值的時候就可以大大加快速度
OK,上代碼:
type tpoint=^tppoint;
tppoint=record
l,r,mid:longint;
max:longint;
lc,rc:tpoint;
end;
edge=record s,t:longint;end;
var e:array[1..500000]of edge;
p,q,f:array[1..100000]of longint;
head:tpoint;
n,m,i,j,k:longint;
procedure sort(l,r: longint);
var i,j:longint;x,y:edge;
begin
i:=l;
j:=r;
x:=e[(l+r) div 2];
repeat
while (e[i].s<x.s)or(e[i].s=x.s)and(e[i].t>x.t) do
inc(i);
while (x.s<e[j].s)or(x.s=e[j].s)and(x.t>e[j].t) do
dec(j);
if not(i>j) then
begin
y:=e[i];
e[i]:=e[j];
e[j]:=y;
inc(i);
j:=j-1;
end;
until i>j;
if l<j then
sort(l,j);
if i<r then
sort(i,r);
end;
function max(a,b:longint):longint;
begin
if a>b then exit(a) else exit(b);
end;
procedure build(var p:tpoint;l,r:longint);
begin
new(p);
p^.l:=l;
p^.r:=r;
p^.mid:=(l+r)div 2;
if l=r then
begin
p^.max:=0;
p^.lc:=nil;
p^.rc:=nil;
exit;
end;
build(p^.lc,l,p^.mid);
build(p^.rc,p^.mid+1,r);
p^.max:=0;
end;
procedure update(var p:tpoint;x,value:longint);
begin
if p^.l=p^.r then
begin
p^.max:=value;
exit;
end;
if x<=p^.mid then update(p^.lc,x,value)
else update(p^.rc,x,value);
p^.max:=max(p^.lc^.max,p^.rc^.max);
end;
function query(p:tpoint;l,r:longint):Longint;
var ans:longint;
begin
if l>r then exit(0);
if p=nil then exit(0);
if p^.r<=r then
exit(p^.max);
ans:=query(p^.lc,l,r);
if p^.mid+1<=r then ans:=max(ans,query(p^.rc,l,r));
exit(ans);
end;
begin
read(n,m);
if m=0 then
begin
writeln(0);
exit;
end;
build(head,1,n);
for i:=1 to m do
read(e[i].s,e[i].t);
for i:=1 to n do
read(q[i]);
for i:=1 to n do
read(p[i]);
sort(1,m);
for i:=1 to m do
begin
if e[i].t<>1 then k:=query(head,1,e[i].t-1)+p[e[i].s]+q[e[i].t]
else k:=p[e[i].s]+q[1];
if k>f[e[i].t] then
begin
update(head,e[i].t,k);
f[e[i].t]:=k;
end;
end;
writeln(query(head,1,n));
end.
代碼片:https://code.csdn.net/snippets/1567138