基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题
收藏
关注
它想选择其中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 31 2 3 4 64 52 5 1 4
Output示例
10
这里的交区间是k个区间都相交的区间
输入
5 3 3
1 2 3 4 5
1 2
2 3
2 5
输出
2
把所有区间按照左端点排序,枚举每一个区间把其左端点当着交区间的左端点,用线段树找到交区间右端点,更新答案
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#define maxn 100005
#define MOD 1000000007
using namespace std;
typedef long long ll;
struct Node{
friend bool operator < (const Node &a, const Node&b){
return a.l < b.l;
}
int l, r;
}node[maxn];
int num[maxn<<2];
ll sum[maxn];
void Update(int n, int l, int r, int h){
if(l == r){
num[n]++;
return ;
}
int mid = (l + r) >> 1;
if(h <= mid)
Update(n<<1, l, mid, h);
else
Update(n<<1|1, mid+1, r, h);
num[n] = num[n<<1] + num[n<<1|1];
}
int Query(int n, int l, int r, int k){
if(l == r){
return l;
}
int mid = (l + r) >> 1;
if(num[n<<1|1] >= k)
return Query(n<<1|1, mid+1, r, k);
else
return Query(n<<1, l, mid, k - num[n<<1|1]);
}
int main(){
// freopen("in.txt", "r", stdin);
int n, k, m;
scanf("%d%d%d", &n, &k, &m);
for(int i = 1; i <= n; i++){
scanf("%I64d", sum+i);
sum[i] += sum[i-1];
}
for(int i = 1; i <= m; i++)
scanf("%d%d", &node[i].l, &node[i].r);
sort(node+1, node+1+m);
for(int i = 1; i <= k; i++){
Update(1, 1, n, node[i].r);
}
ll ans = 0;
for(int i = k; i <= m; i++){
int s = Query(1, 1, n, k);
if(s >= node[i].l && s <= node[i].r)
ans = max(ans, sum[s] - sum[node[i].l-1]);
if(i != m)
Update(1, 1, n, node[i+1].r);
}
printf("%I64d\n", ans);
return 0;
}