4094: [Usaco2013 Dec]Optimal Milking
Description
Farmer John最近购买了N(1 <= N <= 40000)台挤奶机,编号为1 ... N,并排成一行。第i台挤奶机每天能够挤M(i
)单位的牛奶 (1 < =M(i) <=100,000)。由于机器间距离太近,使得两台相邻的机器不能在同一天使用。Farmer Jo
hn可以自由选择不同的机器集合在不同的日子进行挤奶。在D(1 < = D < = 50,000)天中,每天Farmer John对某一
台挤奶机进行维护,改变该挤奶机的产量。Farmer John希望设计一个挤奶方案,使得挤奶机能够在D天后获取最多
的牛奶。
Input
第1行:两个整数N和D
第2..N+1行:每台挤奶机的M(i)
第N+2..N+D+1行:两个整数i和m,表示每天对机器i进行维护,机器i的产量为m。
Output
最大产量
Sample Input
5 3
1
2
3
4
5
5 2
2 7
1 10
1
2
3
4
5
5 2
2 7
1 10
Sample Output
32
【样例解释】
第1天,最优方案为2+4=6 ( 方案1+3+2一样)
第2天,最优方案为7+4=11
第3天,最优方案为10+3+2=15
思路:
小白逛公园做过没有,一样的题,单点修改全局查询区间合并线段树裸题;
我们设t为区间最大值, lt为强制不选最左结点的最大值, rt为强制不选右结点的最大值,d为强制不选两端点的最大值。
pushup很好想。
下面是代码:
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #define ls p<<1 #define rs p<<1|1 using namespace std; const int N = 41000; int n, d, a[N]; class Segment_Tree { public: int t[N<<2], lt[N<<2], rt[N<<2], d[N<<2]; inline void Pushup(int p) { t[p] = max(t[ls]+lt[rs], t[rs]+rt[ls]); lt[p] = max(d[ls]+t[rs], lt[ls]+lt[rs]); rt[p] = max(d[rs]+t[ls], rt[ls]+rt[rs]); d[p] = max(lt[ls]+d[rs], d[ls]+rt[rs]); } void Build(int l, int r, int p) { if(l==r) { t[p] = a[l]; return ; } int mid = (l+r) >> 1; Build(l, mid, ls); Build(mid+1, r, rs); Pushup(p); } void Change(int l, int r, int p, int x, int c) { if(l==r) { a[l] = c; t[p] = c; return ; } int mid = (l+r) >> 1; if(x<=mid) Change(l, mid, ls, x, c); else Change(mid+1, r, rs, x, c); Pushup(p); } }Tr; long long ans = 0; class Init_Solve { public: void init() { scanf("%d%d",&n,&d); for(int i=1;i<=n;i++) scanf("%d",&a[i]); Tr.Build(1, n, 1); for(int i=1;i<=d;i++) { int x, c; scanf("%d %d", &x, &c); Tr.Change(1, n, 1, x, c); ans+=Tr.t[1]; } printf("%lld ",ans); } }Is; int main() { Is.init(); }