ProblemDescription
小
A
有一个含有
它想选择其中
k
个区间, 使得这些区间的交的那些位置所对应的数的和最大。
例如样例中,选择
Input
多组测试数据
第一行三个数
n,k,m(1≤n≤100000,1≤k≤m≤100000)
。
接下来一行
n
个数
接下来
m
行,每行两个数
Output
一行表示答案
Source
2016 ”百度之星” - 初赛( AstarRound2B )
区间题一般思路:定(枚举)区间左端点,计算(递推)区间右端点。
这题明显枚举区间交的左端点,并有一个显然的结论:交区间的左端点一定是某个区间的左端点(所有项非负)。
因为所有项都是非负的,所以定了左端点后,直接尽量长地延伸就好。
而且这是个区间交,所以选定的
k
个区间的左端点一定不在区间交的左端点右侧。
所以就枚举
#include<stdio.h>
#include<algorithm>
#define N 100050
int q[N],n,k,m,l;
long long s[N],ans;
struct seg{int l,r;}b[N];
inline void swap(int &a,int &b){a=a^b;b=a^b;a=a^b;}
inline bool cmp(const seg &a,const seg &b){return a.l<b.l;}
inline void up(int i){for (int j=i>>1;i>1;j=i>>1) if (q[i]<q[j]) swap(q[i],q[j]),i=j;else return;}
inline void down(int i)
{
for (int j=i<<1;j<=l;j=i<<1)
{
if (q[j+1]<q[j] && j<l) j++;
if (q[j]<q[i]) swap(q[i],q[j]),i=j;
else return;
}
}
int main()
{
while (~scanf("%d%d%d",&n,&k,&m))
{
l=ans=0;
for (int i=1,j;i<=n;i++) scanf("%d",&j),s[i]=s[i-1]+j;
for (int i=0;i<m;i++) scanf("%d%d",&b[i].l,&b[i].r);
std::sort(b,b+m,cmp);
for (int i=0;i<m;i++)
{
if (l==k) {q[1]=q[l--],down(1);q[++l]=b[i].r,up(l);}
else q[++l]=b[i].r,up(l);
if (l==k) ans=(ans<s[q[1]]-s[b[i].l-1])?s[q[1]]-s[b[i].l-1]:ans;
}
printf("%I64d\n",ans);
}
}