题目传送门:3300: 抢银行 -- Power OJ
样例输入:
3
1 0 0
2 0 1
3 1 1
样例输出:4
解题思路:
题目很有意思,抛开抢劫的条件不谈,这题肯定就是一个贪心水题,但是因为有这个条件,反而有点无从下手,仔细想想,这题可以用dp来做,首先用一个结构体h[i]存储第i个银行对应的抢劫条件以及价值,用dp[i]表示的就是抢劫第i个银行所能得到的最大价值,那么我们的状态转移方程就能很容易的写出来:;由于要遍历从h[i].l到h[i].r的dp值,出题者肯定会卡你这里的时间,笔者也是乱冲导致T2了,那么怎样优化呢,想到要求取区间内的最大值,那自然是线段树没跑了,开一个线段树,维护区间最大值,每次查询h[i].l到h[i].r的最大值后,将dp[i]算出来,接着更新线段树。遍历n次,答案就是dp[i]的max值,值得注意的这题的答案不是dp[n],它最大的时候万一不是抢第n个银行呢,对吧。
AC代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
#include <map>
#include <unordered_map>
using namespace std;
#define LL long long
#define ll (now<<1|1)
#define rr ll+1
#define mid ((l+r)>>1)
const int N=2e5+10;
LL tree[4*N];
int n,a[N];
LL dp[N];
struct node{
int l,r;
LL w;
}h[N];
void update(int idx,LL val,int now=0,int l=0,int r=n)//区间查询
{
if(idx<l||idx>r) return;
if(idx==l&&l==r) tree[now]=val;
else{
update(idx, val,ll,l,mid);
update(idx, val,rr,mid+1,r);
tree[now]=max(tree[ll], tree[rr]);
}
}
LL query(int idxl,int idxr,int now=0,int l=0,int r=n)//单点修改
{
if(l>=idxl&&r<=idxr) return tree[now];
else{
if(idxr<=mid) return query(idxl, idxr,ll,l,mid);
else if (idxl>mid) return query(idxl, idxr,rr,mid+1,r);
return max(query(idxl, idxr,ll,l,mid), query(idxl, idxr,rr,mid+1,r));
}
}
int main()
{
scanf("%d",&n);
for (int i=1; i<=n; i++) scanf("%lld%d%d",&h[i].w,&h[i].l,&h[i].r);
for (int i=1; i<=n; i++) {
dp[i]=query(h[i].l, h[i].r)+h[i].w;
update(i, dp[i]);
}
LL ans=0;
for (int i=1; i<=n; i++) {
ans=max(ans, dp[i]);//获得答案
}
printf("%lld\n",ans);
return 0;
}