原题链接



1672 区间交



基准时间限制: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;
}