GDKOI2015D2T1

題目大意:有一個二分圖,對於左邊的第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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章