区间交
题意:选择k个区间使得区间交里面的和最大。
思路:先把区间按l从小到大排序,找到至少有k条线段覆盖到的最右边的位置。用线段树维护,最后更新答案即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct node{
int l,r;
}a[100005];
ll b[100005];
int sum[400005];
int cmp(node x,node y){
if(x.l==y.l)
return x.r<y.r;
return x.l<y.l;
}
int ql;
void up(int o,int l,int r){
if(l==r){
sum[o]++;
return;
}
int m=(r+l)>>1;
if(ql<=m)
up(o*2,l,m);
else up(o*2+1,m+1,r);
sum[o]=sum[o*2]+sum[o*2+1];
}
int qu(int o,int l,int r){
if(l==r)
return r;
int m=(l+r)>>1;
if(sum[o*2+1]>=ql)
qu(o*2+1,m+1,r);
else{
ql-=sum[o*2+1];
qu(o*2,l,m);
}
}
int main(){
int n,k,m;
while(~scanf("%d%d%d",&n,&k,&m)){
int x;
b[0]=0;
for(int i=1;i<=n;i++){
scanf("%d",&x);
b[i]=b[i-1]+x;
}
for(int i=0;i<m;i++)
scanf("%d%d",&a[i].l,&a[i].r);
sort(a,a+m,cmp);
memset(sum,0,sizeof(sum));
for(int i=0;i<k-1;i++){
ql=a[i].r;
up(1,1,n);
}
ll ans=0;
for(int i=k-1;i<m;i++){
ql=a[i].r;
up(1,1,n);
ql=k;
int t=qu(1,1,n);
ans=max(ans,b[t]-b[a[i].l-1]);
}
printf("%lld\n",ans);
}
}