hdu 5700 难度:一般

点击打开链接

区间交

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1263    Accepted Submission(s): 490


Problem Description

小A有一个含有n个非负整数的数列与m个区间。每个区间可以表示为li,ri。
它想选择其中k个区间, 使得这些区间的交的那些位置所对应的数的和最大。
例如样例中,选择[2,5]与[4,5]两个区间就可以啦


多组测试数据
第一行三个数n,k,m(1≤n≤100000,1≤k≤m≤100000)。
接下来一行n个数ai,表示lyk的数列(0≤ai≤109)。
接下来m行,每行两个数li,ri,表示每个区间(1≤li≤ri≤n)。


Sample Input

 
 
5 2 3 1 2 3 4 6 4 5 2 5 1 4

Sample Output

 
 
10

这个题用了贪心的思想,思路是将左区间从小到大排序,从第k的左区间开始,查找这些区间中第k大的右区间,然后

记录该区间的值与最大做比较,从第k个左区依次类推,每次计算一次区间值之前都要先更新当前的右区间,可以用

线段树更新

#include<cstdio>
#include<cstring>
#include<algorithm>
#define max(x,y) x>y?x:y
using namespace std;
struct node
{
	int l,r;
}a[100001];
int tree[300000];
long long sum[100001];
long long ans;
bool cmp(node c,node d)
{
	return c.l<d.l;
}
void update(int l,int r,int node,int pos)
{
	if(l==r)
	{
		tree[node]++;
		return;
	}
	int m=(l+r)/2;
	if(m>=pos)
	update(l,m,node*2,pos);
	else
	update(m+1,r,node*2+1,pos);
	tree[node]=tree[node*2]+tree[node*2+1];
}
int query(int l,int r,int node,int key)
{
	if(l==r)
	return l;
	int m=(l+r)/2;
	if(tree[node*2+1]>=key)
	return query(m+1,r,node*2+1,key);
	else
	return query(l,m,node*2,key-tree[node*2+1]);//如果右子树保存的右区间数少于k,就在左子树寻找第k-tree[node]个右区间 
}
int main()
{
	int n,m,k;
	while(~scanf("%d%d%d",&n,&k,&m))
	{
		int i,t;
		sum[0]=0;
		for(i=1;i<=n;i++)
		{
			scanf("%d",&t);
			sum[i]=sum[i-1]+t;//计算前i个数的和 
		}
		for(i=1;i<=m;i++)
		scanf("%d%d",&a[i].l,&a[i].r);
		sort(a+1,a+m+1,cmp);
		memset(tree,0,sizeof(tree));//初始化线段树 
		for(i=1;i<k;i++)
		{
			update(1,n,1,a[i].r);//往线段树中插入右区间位置 
		}
		ans=0;
		for(i=k;i<=m;i++)
		{
			update(1,n,1,a[i].r);
			t=query(1,n,1,k);//查找当前线段树保存的右区间中能最靠右的右区间 
			ans=max(ans,sum[t]-sum[a[i].l-1]);
		}
		printf("%lld\n",ans);
	}
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长沙橘子猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值