【51Nod - 1672】【区间交】

版权声明:本人原创,未经许可,不得转载 https://blog.csdn.net/qq_42505741/article/details/83500976

题目:

小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

一行表示答案

Sample Input

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

Sample Output

10

解题报告:贪心,之前刚接触这道题目是完全没有想法的,因为穷搜百分之百会超时,所以在挣扎之后,选择了参考题解,见了一种新的stl容器  multiset 这个是set的特殊形式,特殊在他可以存放相同数值的元素(set中会自动抹去),之后就是贪心,每次将区间的右端点压入multiset,(自动帮我们排为升序)和左端点进行比较,如果是左端点大于之前multiset中最小的右端点的话,抹去它,如果结束时候长度大于k 抹去前端。最后输出这个区间的最大值。

ac代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<set>
#include<algorithm>
using namespace std;
typedef long long ll;

const int maxn=1e5+100;
ll sum[maxn];
struct node{
	int l,r;
}nod[maxn];
bool cmp(node a,node b)
{
	return a.l<b.l;
}

int main()
{
	int n,k,m;
	while(scanf("%d%d%d",&n,&k,&m)!=EOF)
	{
		int x;
		memset(sum,0,sizeof(sum));
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&x);
			sum[i]=sum[i-1]+x;
		}
		for(int i=1;i<=m;i++)
		{
			scanf("%d%d",&nod[i].l,&nod[i].r);
		}
		sort(nod+1,nod+1+m,cmp);
		multiset<int > s;
		ll ans=0;
		for(int i=1;i<=m;i++)
		{
			int l=nod[i].l,r=nod[i].r;
			s.insert(r);
			while(s.size())
			{
				if(*s.begin()<l) s.erase(s.begin());
				else break;
			}
			while(s.size()>k)
			{
				s.erase(s.begin());
			}
			if(s.size()==k)
			{
				ans=max(ans,sum[*s.begin()]-sum[l-1]);
			}
		}
		printf("%lld\n",ans);
	}	
	return 0;
} 

上边是利用stl的贪心解法,下面这个是线段树求解,按照将么个区间左端点作为所找区间的左端点,看看他的右端点将会跑到哪,进行线段树求解,寻找出最大值。(= =) (线段树遗忘的很多,打算补后再细分析)

ac代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<queue>
using namespace std;
typedef long long ll;

const int maxn=1e5+100;
int num[maxn<<2];
ll sum[maxn<<1];

struct node{
	friend bool operator < (const node &a,const node &b){
		return a.l<b.l;
	}
	int l,r;
}nod[maxn];

void updata(int n,int l,int r,int h)
{
	if(l==r)
	{
		num[n]++;
		return ;
	}
	int mid=(l+r)>>1;
	if(h<=mid)
		updata(n<<1,l,mid,h);
	else
		updata(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()
{
	int n,k,m;
	scanf("%d%d%d",&n,&k,&m);
	for(int i=1;i<=n;i++)
		scanf("%lld",&sum[i]),sum[i]+=sum[i-1];
	for(int i=1;i<=m;i++)
		scanf("%d%d",&nod[i].l,&nod[i].r);
	sort(nod+1,nod+1+m);
	for(int i=1;i<=k;i++)
	{
		updata(1,1,n,nod[i].r);
	}
	ll ans=0;
	for(int i=k;i<=m;i++)
	{
		int s=query(1,1,n,k);
		if(s>=nod[i].l&&s<=nod[i].r)
			ans=max(ans,sum[s]-sum[nod[i].l-1]);
		if(i!=m)
			updata(1,1,n,nod[i+1].r);
	}
	printf("%lld\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42505741/article/details/83500976