【线段树dp】115E - Linear Kingdom Races

http://codeforces.com/problemset/problem/115/E

题目大意,给你1~n段路,每段路修好需要一定代价,同时给m个区间,如果连续修好li~ri的所有路就可以获得pi的收益,询问最大利润。

想了一会,发现除了暴力的dp没有其他办法,但是10^5级别让n^2的dp无能为力,后来看到题目旁边datastruct+dp的提示,想到用线段树来优化dp的方法。

k表示当前区间,dp[i]:表示从第i段路修到当前路段全部修好的最大收益。

如果某一个比赛区间[Li,Ri]右端点刚好为当前区间,则显然dp[1]~dp[Li] 全部要加上pi;

再考虑当前区间移到下一个区间时候,dp[k+1]=当前最优解-cost[k+1],  同时dp[1]~dp[k]都需要减掉cost[k+1].

最后考虑更新当前最优解,ans = max( ans , dp[1],dp[2]...dp[k] );

到此,发现dp所有操作均能用线段树优化成O(logn)...

 1 //By Lin
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define maxn 200005
 6 using namespace std;
 7 typedef long long LL;
 8 
 9 struct    Node{
10     int left ,right;
11     LL    key,ma;
12 }tree[maxn*4];
13 void    build(int left ,int right ,int step ) {
14     tree[step].left = left; tree[step].right = right;
15     if ( left == right ) return;
16     int mid = ( left + right)/2;
17     build( left , mid , step*2 );
18     build(mid+1 ,right, step*2+1 );
19 }
20 void    down(int step ) {
21     if ( tree[step].key == 0 ) return;
22     LL key = tree[step].key;
23     tree[step].key = 0; 
24     tree[step*2].key += key;
25     tree[step*2].ma  += key;
26     tree[step*2+1].key += key;
27     tree[step*2+1].ma  += key;
28 }
29 void    updata(int left , int right , LL key , int step ) {
30     if ( tree[step].left == left && tree[step].right == right ) {
31         tree[step].key += key; 
32         tree[step].ma  += key;
33         return;
34     }
35     down(step);
36     int mid = ( tree[step].left + tree[step].right )/2;
37     if ( right <= mid ) updata( left,right,key, step*2 );
38     else if ( left > mid ) updata( left,right,key,step*2+1 );
39     else {
40         updata( left , mid , key , step*2 );
41         updata(mid+1 ,right, key , step*2+1 );
42     }
43     tree[step].ma = max( tree[step*2].ma , tree[step*2+1].ma );
44 }
45 LL        ask( int left ,int right , int step ) {
46     if ( tree[step].left == left && tree[step].right == right ) return tree[step].ma;
47     down( step );
48     int mid = ( tree[step].left + tree[step].right )/2;
49     if ( right <= mid ) return ask(left,right,step*2);
50     else if ( left > mid ) return ask(left,right,step*2+1);
51     else return max(ask(left,mid,step*2),ask(mid+1,right,step*2+1));
52 }
53 
54 int        n,m,c[maxn];
55 struct    node{
56     int l , r , p;
57 }data[maxn];
58 bool    cmp( const node &a , const node &b ) {
59     return a.r < b.r;
60 }
61 int        main(){
62     scanf("%d%d", &n, &m );
63     for (int i = 1; i<=n; i++) scanf("%d", &c[i] );
64     for (int i = 0; i<m; i++) scanf("%d%d%d", &data[i].l, &data[i].r, &data[i].p );
65     sort( data , data+m , cmp );
66     build(0,n,1);
67     LL    ans = 0; 
68     for (int i = 1,k=0; i<=n; i++ ) {
69         updata(i,i,ans,1);
70         updata(1,i,-c[i],1);
71         while ( k<m && data[k].r == i ) {
72             updata(1,data[k].l,data[k].p,1);
73             k++;
74         }
75         ans = max( ans , ask(1,n,1) );
76 //        printf("%d %d:" , i , k );
77 //        for (int j = 1; j<=i; j++) printf("%lld ", ask(j,j,1) ); puts("");
78     }
79     printf("%lld\n" , ans );
80     return 0;
81 }
posted @ 2012-11-24 22:57  lzqxh  阅读(287)  评论(0编辑  收藏  举报