小A有一个含有n个非负整数的数列与m个区间,每个区间可以表示为li,ri。
它想选择其中k个区间, 使得这些区间的交的那些位置所对应的数的和最大。(是指k个区间共同的交,即每个区间都包含这一段,具体可以参照样例)
在样例中,5个位置对应的值分别为1,2,3,4,6,那么选择[2,5]与[4,5]两个区间的区间交为[4,5],它的值的和为10。
Input
第一行三个数n,k,m(1<=n<=100000,1<=k<=m<=100000)。 接下来一行n个数ai,表示小A的数列(0<=ai<=10^9)。 接下来m行,每行两个数li,ri,表示每个区间(1<=li<=ri<=n)。
Output
一行表示答案
Input示例
5 2 3 1 2 3 4 6 4 5 2 5 1 4
Output示例
10
Joe
(题目提供者)
C++的运行时限为:1000 ms ,空间限制为:131072 KB
示例及语言说明请按这里
允许其他 AC 的用户查看此代码,分享代码才能查看别人的代码并有机会获得勋章
刚开始想着二分搞搞,然后各种小细节和问题,debug了半天果断换方法,想着还是拿线段树搞搞吧,我们可以枚举区间,每遇到一个区间便把当前区间右端点加入线段树,这样我们就能枚举左端点来求解最大值了,当然,前k-1个左端点不用枚举。。。。
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<string>
#include<math.h>
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<functional>
using namespace std;
typedef long long ll;
#define inf 1000000000
#define mod 1000000007
#define maxn 886000
#define PI 3.1415926
#define lowbit(x) (x&-x)
#define eps 1e-9
ll sum[maxn], a[maxn], sm[maxn];
struct node
{
ll l, r;
}b[maxn];
bool comp(node a, node b)
{
if (a.l == b.l)
return a.r < b.r;
return a.l < b.l;
}
void update(ll id, ll l, ll r, ll x)
{
if (l == r)
{
sum[id]++;
return;
}
ll mid = (l + r) / 2;
if (mid >= x)
update(id * 2, l, mid, x);
else
update(id * 2 + 1, mid + 1, r, x);
sum[id] = sum[id * 2] + sum[id * 2 + 1];
}
ll query(ll id, ll l, ll r, ll x)
{
if (l == r)
return l;
ll mid = (l + r) / 2;
if (sum[id * 2 + 1] >= x)
return query(id * 2 + 1, mid + 1, r, x);
else
return query(id * 2, l, mid, x-sum[id*2+1]);
}
int main(void)
{
ll ans = 0;
ll n, m, k, i, j;
scanf("%lld%lld%lld", &n, &k, &m);
for (i = 1;i <= n;i++)
{
scanf("%lld", &a[i]);
sm[i] = sm[i - 1] + a[i];
}
for (i = 1;i <= m;i++)
scanf("%lld%lld", &b[i].l, &b[i].r);
sort(b + 1, b + m + 1, comp);
for (i = 1;i < k;i++)
update(1, 1, n, b[i].r);
for (i = k;i <= m;i++)
{
update(1, 1, n, b[i].r);
ll pos = query(1, 1, n, k);
if (pos >= b[i].l)
ans = max(ans, sm[pos] - sm[b[i].l - 1]);
}
printf("%lld\n", ans);
return 0;
}