区间交
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1423 Accepted Submission(s): 543
Problem Description
小A有一个含有n个非负整数的数列与m个区间。每个区间可以表示为li,ri。
它想选择其中k个区间, 使得这些区间的交的那些位置所对应的数的和最大。
例如样例中,选择[2,5]与[4,5]两个区间就可以啦。
Input
多组测试数据
第一行三个数n,k,m(1≤n≤100000,1≤k≤m≤100000)。
接下来一行n个数ai,表示lyk的数列(0≤ai≤109)。
接下来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
思路:将左端点进行排序,然后我们枚举左端点作为区间交的左端点,要选择选k个区间,那么前k-1个就不用枚举了,然后找有右端点,我们可以发现越右边覆盖区间越长,用cover数组来标记出现了几次,然后用线段树来更新。当然也可以用优先队列来写思路差不多。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=100000+10;
int cover[N<<2];
ll sum[N<<2];
struct node
{
int l,r;
friend bool operator <(node a,node b)
{
return a.l<b.l;
}
}a[N];
void update(int l,int r,int x,int k)
{
if(l==r)
{
cover[x]++;
return;
}
int mid=(l+r)/2;
if(k<=mid)update(l,mid,x*2,k);
else update(mid+1,r,x*2+1,k);
cover[x]=cover[x*2]+cover[x*2+1];
}
int query(int l,int r,int x,int k)
{
if(l==r)
return l;
int mid=(l+r)/2;
if(cover[x*2+1]>=k)return query(mid+1,r,x*2+1,k);//优先从右边找
else return query(l,mid,x*2,k-cover[x*2+1]);
}
int main()
{
int n,k,m;
while(~scanf("%d%d%d",&n,&k,&m))
{
memset(sum,0,sizeof(sum));
memset(cover,0,sizeof(cover));
for(int i=1;i<=n;i++)
{
ll x;
scanf("%lld",&x);
sum[i]=sum[i-1]+x;
}
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a[i].l,&a[i].r);
}
sort(a+1,a+m+1);
for(int i=1;i<k;i++)
{
update(1,n,1,a[i].r);
}
ll ans=0;
for(int i=k;i<=m;i++)
{
update(1,n,1,a[i].r);
int qq=query(1,n,1,k);
if(qq>=a[i].l)
{
ans=max(ans,sum[qq]-sum[a[i].l-1]);
}
}
printf("%lld\n",ans);
}
return 0;
}
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=100000+10;
struct node
{
int l,r;
friend bool operator < (node a,node b)
{
return a.l<b.l;
}
}a[maxn];
priority_queue<int,vector<int>,greater<int> >q;
ll sum[maxn];
int main()
{
int n,k,m;
while(~scanf("%d%d%d",&n,&k,&m))
{
while(!q.empty())q.pop();
ll x;
memset(sum,0,sizeof(sum));
for(int i=1;i<=n;i++)
{
scanf("%lld",&x);
sum[i]=sum[i-1]+x;
}
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a[i].l,&a[i].r);
}
ll mx=0;
sort(a+1,a+1+m);
for(int i=1;i<=m;i++)
{
q.push(a[i].r);
if(q.size()<k)continue;
if(q.size()>k)q.pop();
mx=max(mx,sum[q.top()]-sum[a[i].l-1]);
}
printf("%lld\n",mx);
}
return 0;
}