点击打开题目
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 811 Accepted Submission(s): 364
Problem Description
小A有一个含有 个非负整数的数列与 个区间。每个区间可以表示为 。 它想选择其中 个区间, 使得这些区间的交的那些位置所对应的数的和最大。 例如样例中,选择 与 两个区间就可以啦。
Input
多组测试数据 第一行三个数 。 接下来一行 个数 ,表示lyk的数列 。 接下来 行,每行两个数 ,表示每个区间 。
Output
一行表示答案
Sample Input
5 2 3
1 2 3 4 6
4 5
2 5
1 4
Sample Output
10
Source
2016"百度之星" - 初赛(Astar Round2B)
在上一篇博客分析过了,传送门:点击打开链接
代码如下:
#include <stdio.h>
#include <cstring>
#include <algorithm>
using namespace std;
#define CLR(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define LL long long
#define MAX 100000
#define L o<<1
#define R o<<1|1
LL sum[MAX+5];
struct node
{
int st,endd;
}a[MAX+5];
struct Tree
{
int l,r;
int cover;
}tree[MAX<<2];
bool cmp(node a,node b)
{
return a.st < b.st;
}
void PushUp(int o)
{
tree[o].cover = tree[L].cover + tree[R].cover;
}
void Build(int o,int l,int r)
{
tree[o].l = l;
tree[o].r = r;
if (l == r)
{
tree[o].cover = 0; //覆盖点全部初始化为0
return;
}
int mid = (l + r) >> 1;
Build(L , l , mid);
Build(R , mid + 1 , r);
PushUp(o);
}
void UpDate(int o,int x) //x位置cover值加一
{
if (tree[o].l == tree[o].r)
{
tree[o].cover++;
return;
}
int mid = (tree[o].l + tree[o].r) >> 1;
if (mid >= x)
UpDate(L , x);
else
UpDate(R , x);
PushUp(o);
}
int Query(int o,int x) //满足条件的最靠右的端点下标
{
if (tree[o].l == tree[o].r)
return tree[o].l;
if (tree[R].cover >= x) //优先从右树中找满足条件的
return Query(R , x);
else
return Query(L , x-tree[R].cover); //右边不够剩下的点从左树找
}
int main()
{
int n,k,m;
int t;
while (~scanf ("%d %d %d",&n,&k,&m))
{
sum[0] = 0;
for (int i = 1 ; i <= n ; i++)
{
scanf ("%d",&t);
sum[i] = sum[i-1] + t;
}
for (int i = 1 ; i <= m ; i++)
scanf ("%d %d",&a[i].st,&a[i].endd);
sort (a+1 , a+1+m , cmp); //对左端点排序
Build(1,1,n);
for (int i = 1 ; i <= k ; i++) //前k-1个数的左端点不用枚举,直接更新其右端点即可
UpDate(1,a[i].endd);
LL ans = 0;
a[m+1].endd = 1; //随便赋值一个,防止最后一次循环出问题
for (int i = k ; i <= m ; i++) //从第k个点开始
{
int pos = Query(1,k);
if (pos >= a[i].st)
ans = max (ans , sum[pos] - sum[a[i].st-1]);
UpDate(1,a[i+1].endd); //将下一点的右端点加入,即其cover值加一
}
printf ("%lld\n",ans);
}
return 0;
}