51nod 1611 金牌赛事(动态规划 + 线段树)

Posted 7391_KID

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了51nod 1611 金牌赛事(动态规划 + 线段树)相关的知识,希望对你有一定的参考价值。

分析:看起来有点像最大权闭合图,然而复杂度太高。。。

正解是dp,设dp[i]为考虑前i条路的最大收益,则dp[i]=max{dp[j] - cost[j+1][i] + earn[j+1][i]},0<=j<=i-1,earn[j+1][i]表示在[j+1,i]之间的比赛,是个O(n^2)的dp.

接下来考虑优化这个dp.维护一个线段树,当扫到i时,树中满足a[j] = dp[j] - cost[j+1][i] + earn[j+1][i],先将比赛按右端点排序,然后每扫到一个右端点为i的比赛,将所有j<l的a[j] 加上earn,将所有j<i的a[i]减去c[i],然后更新dp[i]为[0,i-1]的最大值。复杂度为O(nlogn)。

  1 #include<iostream>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<cstdio>
  5 using namespace std;
  6 typedef long long ll;
  7 const int maxn=2e5+5;
  8 const ll inf = 1e18;
  9 struct Contest{
 10     int l,r;
 11     ll earn;
 12 }p[maxn];
 13 int n, m;
 14 //bool Cmp(Pair a,Pair b){return a.r-a.l<b.r-b.l;}
 15 bool Cmp(Contest a, Contest b){return a.r < b.r;}
 16 class segTree{
 17     ll a[maxn],s[maxn*4],tag[maxn*4];
 18 public:
 19     segTree(){memset(a,0,sizeof(a));}
 20     void build(int node,int begin,int end){
 21         tag[node]=0;
 22         if(begin==end){
 23             s[node]=a[begin];
 24         }else{
 25             build(2*node,begin,(begin+end)/2);
 26             build(2*node+1,(begin+end)/2+1,end);
 27             s[node]=max(s[2*node],s[2*node+1]);
 28         }
 29     }
 30     void pushdown(int node,int begin,int end){
 31         if(begin==end){
 32             s[node]+=tag[node];
 33             a[begin]=s[node];
 34         }else{
 35             tag[2*node]+=tag[node];
 36             tag[2*node+1]+=tag[node];
 37             s[node]+=tag[node];
 38         }
 39         tag[node]=0;
 40     }
 41     void Change(int node,int begin,int end,int left,int right,ll add){
 42         if(begin>=left&&end<=right){
 43             tag[node]+=add;
 44         }else{
 45             pushdown(node,begin,end);
 46             int m=(begin+end)/2;
 47             if(!(right<begin||left>m)){
 48                 Change(2*node,begin,m,left,right,add);
 49             }
 50             if(!(right<m+1||left>end)){
 51                 Change(2*node+1,m+1,end,left,right,add);
 52             }
 53             s[node] = max(s[2 * node] + tag[2 * node], s[2 * node + 1] + tag[2 * node + 1]);
 54         }
 55     }
 56     ll query(int node,int begin,int end,int left,int right){
 57         pushdown(node,begin,end);
 58         if(begin > right || end < left)return -inf;
 59         if(begin==end)return a[begin];
 60         if(begin >= left && end <= right)return s[node];
 61         ll q1 = query(2 * node, begin, (begin + end) / 2, left, right);
 62         ll q2 = query(2 * node + 1, (begin + end) / 2 + 1, end, left, right);
 63         return max(q1, q2);
 64     }
 65     void Print(){
 66         for(int i = 0; i <= n; i++){
 67             cout<<query(1, 0, n, i, i)<<\' \';
 68         }
 69         cout<<endl;
 70     }
 71 }st;
 72 
 73 ll c[maxn], f[maxn];
 74 int main(){
 75 //    freopen("e:\\\\in.txt","r",stdin);
 76     scanf("%d%d",&n,&m);
 77     for(int i = 1; i <= n; i++)scanf("%lld",&c[i]);
 78     for(int i = 0; i < m; i++)scanf("%d%d%lld",&p[i].l,&p[i].r,&p[i].earn);
 79     sort(p, p + m, Cmp);
 80     int idx = 0;
 81     st.build(1, 0, n);
 82     f[0] = 0;
 83     for(int i = 1; i <= n; i++){
 84         while(idx < m && p[idx].r <= i){
 85             st.Change(1, 0, n, 0, p[idx].l - 1, p[idx].earn);
 86 //            st.Print();
 87             idx++;
 88         }
 89         st.Change(1, 0, n, 0, i - 1, -c[i]);
 90 //        st.Print();
 91         f[i] = st.query(1, 0, n, 0, i - 1);
 92         f[i] = max(f[i - 1], f[i]);
 93         st.Change(1, 0, n, i, i, f[i]);
 94 //        st.Print();
 95 //        cout<<"*********"<<endl;
 96     }
 97 //    for(int i = 0; i <= n; i++)cout<<f[i]<<endl;
 98     cout<<f[n]<<endl;
 99     return 0;
100 }

 

以上是关于51nod 1611 金牌赛事(动态规划 + 线段树)的主要内容,如果未能解决你的问题,请参考以下文章

51Nod1231 记分牌 动态规划

51Nod1518 稳定多米诺覆盖 动态规划 插头dp 容斥原理

51Nod1634 刚体图 动态规划 容斥原理 排列组合

51nod 简单的动态规划

51Nod 1083 矩阵取数问题 | 动态规划

51Nod1317 相似字符串对 容斥原理 动态规划