[cf115E]Linear Kingdom Races

参考了这里:http://blog.sina.com.cn/s/blog_6a6aa7830100x890.html

我们从第一条赛道往后选择,设选择到第i条赛道时最优值是f[i],这里注意f[i]表示的方案中第i条是不一定被选中的。

这里的状态转移分两种,第i条选或不选

1:不选,f[i]=f[i-1]

2:选,设连续往前一直选到第j+1条(0<=j<i),则f[i]=f[j]-cost(j+1,i)+pay(j+1,i)

(cost(j+1,i)表示从j+1到i的赛道全部修复的所需付费,即cost[j+1]+cost[j+2]+...+cost[i],pay(j+1,i)表示所有被完全包含在区间[j+1,i]内的比赛赚的钱总和)

这样我们就得到状态转移方程:

f[i]=max{f[i-1],f[j]-cost(j+1,i)+pay(j+1,i)} (0<=j<i)

初始条件f[0]=0

如果朴素转移的话时间是在O(n^2*m),我们用线段树来维护一下就没了。

(没学过线段树优化dp的可以看下面这一段来入门)

假设一个序列v[j]=f[j]-cost(j+1,i)+pay(j+1,i),只要用线段树维护它的区间[0,i-1]最大值就可以了。观察这个表达式,我们可以发现,当i增加1时,所有它之前的v值都要多减去一个cost[i],同时,对于每一个右端点恰好为i,即r=i的比赛(l,r,p),每一个下标小于l的v值都要加上一个p,换句话说,这是一个区间修改,区间查询的问题。完成状态转移后,将f[i]加入线段树的第i位即可。初始时,v序列中只有一个v[0]=0。不过这个v序列我们显然是不需要去再开一个数组来模拟它了,只是为了说得方便引入的。

cf上似乎没开边界检查?算术上溢的时候自然溢出了。

code:

  1 program cf115E;
  2 type competition=record lb,rb,p:longint; end;
  3 var tree:array[0..600000] of record flag,max:int64; end;
  4     com:array[0..200010] of competition;
  5     cost:array[0..200010] of longint;
  6     f:array[0..200010] of int64;
  7     i,j,n,m:longint;
  8     ans:int64;
  9 procedure sort(l,r:longint);
 10 var i,j,x:longint;
 11     t:competition;
 12 begin
 13   i:=l; j:=r; x:=com[(l+r)shr 1].rb;
 14   repeat
 15     while com[i].rb<x do inc(i);
 16     while com[j].rb>x do dec(j);
 17     if i<=j then
 18       begin
 19         t:=com[i];
 20         com[i]:=com[j];
 21         com[j]:=t;
 22         inc(i);
 23         dec(j);
 24       end;
 25   until i>j;
 26   if i<r then sort(i,r);
 27   if j>l then sort(l,j);
 28 end;
 29 function maxf(a,b:int64):int64;
 30 begin
 31   if a>b then exit(a) else exit(b);
 32 end;
 33 procedure pushdown(x:longint);
 34 begin
 35   tree[x+x].max:=tree[x+x].max+tree[x].flag;
 36   tree[x+x+1].max:=tree[x+x+1].max+tree[x].flag;
 37   tree[x+x].flag:=tree[x+x].flag+tree[x].flag;
 38   tree[x+x+1].flag:=tree[x+x+1].flag+tree[x].flag;
 39   tree[x].flag:=0;
 40 end;
 41 procedure edit_len(x,nowl,nowr,l,r,p:longint);
 42 var mid:longint;
 43 begin
 44   if (nowr<l)or(nowl>r) then exit;
 45   if (l<=nowl)and(nowr<=r) then
 46     begin
 47       with  tree[x] do
 48         begin
 49           flag:=flag+p;
 50           max:=max+p;
 51         end;
 52       exit;
 53     end;
 54   pushdown(x);
 55   mid:=(nowl+nowr)shr 1;
 56   edit_len(x+x,nowl,mid,l,r,p);
 57   edit_len(x+x+1,mid+1,nowr,l,r,p);
 58   tree[x].max:=maxf(tree[x+x].max,tree[x+x+1].max);
 59 end;
 60 procedure edit_point(x,nowl,nowr,posi:longint;p:int64);
 61 var mid:longint;
 62 begin
 63   if nowl=nowr then
 64     begin
 65       tree[x].flag:=p;
 66       tree[x].max:=p;
 67       exit;
 68     end;
 69   pushdown(x);
 70   mid:=(nowl+nowr) shr 1;
 71   if posi<=mid then edit_point(x+x,nowl,mid,posi,p)
 72     else edit_point(x+x+1,mid+1,nowr,posi,p);
 73   tree[x].max:=maxf(tree[x+x].max,tree[x+x+1].max);
 74 end;
 75 function find(x,nowl,nowr,l,r:longint):int64;
 76 var mid:longint;
 77 begin
 78   if (nowr<l)or(nowl>r) then exit(-maxlongint);
 79   if (nowl>=l)and(nowr<=r) then exit(tree[x].max);
 80   pushdown(x);
 81   mid:=(nowl+nowr) shr 1;
 82   find:=maxf(find(x+x,nowl,mid,l,r),find(x+x+1,mid+1,nowr,l,r));
 83 end;
 84 begin
 85   readln(n,m);
 86   for i:=1 to n do readln(cost[i]);
 87   for i:=1 to m do with com[i] do readln(lb,rb,p);
 88   sort(1,m);
 89   f[0]:=0;
 90   ans:=0;
 91   j:=1;
 92   for i:=1 to n do
 93     begin
 94       while com[j].rb=i do
 95         begin
 96           edit_len(1,0,n,0,com[j].lb-1,com[j].p);
 97           inc(j);
 98         end;
 99       edit_len(1,0,n,0,i-1,-cost[i]);
100       f[i]:=find(1,0,n,0,i-1);
101       if f[i-1]>f[i] then f[i]:=f[i-1];
102       edit_point(1,0,n,i,f[i]);
103       if f[i]>ans then ans:=f[i];
104     end;
105   writeln(f[n]);
106 end.

 

posted @ 2016-10-15 23:03 lkmcfj 阅读(...) 评论(...) 编辑 收藏