CodeForces115E Linear Kingdom Races
题目大意:
给你一段区间
[1,n]
[
1
,
n
]
,区间上的每一个点都有一个使用代价
给你一些小区间 当你使用这些小区间时 可以获得报酬
但是要先付出区间上每一个点的代价(每个点的代价只需要付一次就可以多次使用)
问 最大利润是多少
据说是分治题 借鉴了前辈们的题解之后 觉得做法很巧妙
首先说一下这道题目的难以处理的地方吧
多段区间可能会有交集 存在一些情况 是的两个区间单独选择时都是亏本的 但是一起选择时就有利润
因此我们就不能够单独地看某一个区间是否要使用(因为单独看是亏本的 要一起看才能够获利)
解决方法:线段树
不按照一整个一整个的区间进行规划
而是按照右端点的位置进行规划
对于一个区间
[L,R]
[
L
,
R
]
它的决定因素应该是
L−1
L
−
1
的值
因为有
DP[1.....L,R]=DP[1.....L−1]+GET[L,R]
D
P
[
1.....
L
,
R
]
=
D
P
[
1.....
L
−
1
]
+
G
E
T
[
L
,
R
]
那么 如果对于当前区间 我们把当前点
R
R
(按照右端点进行规划)的花费加到 上,然后把收入加到
L−1
L
−
1
上
统计时统计加上这些花费和收入之后的
[1,L−1]
[
1
,
L
−
1
]
的最大值 和
DP[R−1]
D
P
[
R
−
1
]
的做比较
如果 统计得到的最大值更大 说明选择某一些以
R
R
为右端点的区间 就可以得到更优解
反之 如果 的值更大 说明不选择
R
R
和以 为右端点的区间更优
然后将统计出来的最大值加到 R R 点上 作为往后面统计的基础
为什么可行
就按照单独一个区间来看
我们将 的花费全部都加到了对应的
[1,P−1]
[
1
,
P
−
1
]
上,因此在统计时,
L−1
L
−
1
上是一定减去了
[L,R]
[
L
,
R
]
上的花费的
同样的 收入也被加入了上去
因此我们统计时对应的区间是被相应的改动了的
那么对于统计出来的 R R 点的值,就是最优的,并且因为 点的值一定是相比于 R−1 R − 1 更优的,所以说在之后的统计, R R 在统计是一定是比 更优的,因此,之前在 [1,R−1] [ 1 , R − 1 ] 减去的花费/加上的收入 都不会影响到后面的,而此时的 R R 点一定是选择了 之间最优解得到的
并且,因为只有修改操作,并且每次修改的区间都是 [1,L] [ 1 , L ] ,所以说其实单次修改最大操作复杂度就是 O(logn) O ( l o g n )
为什么非得修改完[1,P-1]
因为你不知道 以 R R 为右端点的区间的左端点到底是啥,而修改的时候涉及到的点是 之间的全部点,所以说必须将值修改到 L−1 L − 1 上
放参考代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#define mid (l+r>>1)
#define ls (o<<1)
#define rs (o<<1|1)
#define getchar() (*inp++)
using namespace std;
char INP[1<<25],*inp=INP;
inline int input()
{
char c=getchar();int o;bool f=0;
while(c>57||c<48)f|=(c=='-'),c=getchar();
for(o=0;c>47&&c<58;c=getchar())o=(o<<1)+(o<<3)+c-48;
return f?-o:o;
}
struct node{int l,r;long long c;}race[200123];
bool cmp(node A,node B)
{
if(A.r!=B.r)return A.r<B.r;
return A.l<B.l;
}
long long mx[800123],wait[800123];
int L,R;long long V;
void PD(int o)
{
long long wo=wait[o];
wait[ls]+=wo;wait[rs]+=wo;
mx[ls]+=wo;mx[rs]+=wo;
wait[o]=0;
}
void add(int o,int l,int r)
{
if(L<=l&&r<=R)
{
wait[o]+=V;
mx[o]+=V;
return;
}
PD(o);
if(L<=mid&&l<=R)add(ls,l,mid);
if(L<=r&&mid<R)add(rs,mid+1,r);
mx[o]=max(mx[ls],mx[rs]);
}
long long DP[200123],cost[200123];
int main()
{
//freopen("In.txt","r",stdin);
fread(INP,1,1<<25,stdin);
int n=input(),m=input();
for(int i=1;i<=n;i++)cost[i]=input();
for(int i=1;i<=m;i++)
{
race[i].l=input();
race[i].r=input();
race[i].c=input();
}
sort(race+1,race+m+1,cmp);
int cnt=1;
for(int i=1;i<=n;i++)
{
L=0;R=i-1;V=-cost[i];
add(1,0,n);
while(race[cnt].r==i)
{
R=race[cnt].l-1;V=race[cnt].c;
add(1,0,n);
cnt++;
}
L=R=i;
V=DP[i]=max(DP[i-1],mx[1]);
add(1,0,n);
}
printf("%I64d",DP[n]);
}