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.youkuaiyun.com/snippets/1567138

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值