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 金牌赛事(动态规划 + 线段树)的主要内容,如果未能解决你的问题,请参考以下文章