51nod 1672-区间交(线段树)

基准时间限制:1 秒 空间限制:131072 KB 分值: 40  难度:4级算法题
 收藏
 关注
小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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值