区间交
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 867 Accepted Submission(s): 384
Problem Description
小A有一个含有
n
个非负整数的数列与
m
个区间。每个区间可以表示为
li,ri
。
它想选择其中 k 个区间, 使得这些区间的交的那些位置所对应的数的和最大。
例如样例中,选择 [2,5] 与 [4,5] 两个区间就可以啦。
它想选择其中 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) 。
第一行三个数 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
Source
Recommend
wange2014
解题思路:把区间当左边,维护右端点的第k大值即可
#include<cstring>
#include<iostream>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<string>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=2e5+10;
int n,m,k,x,l,r;
LL sum[maxn],ans;
int s[maxn],nt[maxn],e[maxn],cnt;
int tree[maxn<<3];
void build(int x,int l,int r,int k)
{
tree[x]++;
if (l==r) return;
int mid=(l+r)>>1;
if (k<=mid) build(x<<1,l,mid,k);
else build(x<<1|1,mid+1,r,k);
}
int getsum(int x,int l,int r,int k)
{
if (l==r) return l;
int mid=(l+r)>>1;
if (tree[x<<1|1]>=k) return getsum(x<<1|1,mid+1,r,k);
else return getsum(x<<1,l,mid,k-tree[x<<1|1]);
}
int main()
{
while(~scanf("%d %d %d",&n,&k,&m))
{
memset(tree,0,sizeof(tree));
memset(s,-1,sizeof s);
ans=sum[0]=cnt=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
sum[i]=sum[i-1]+x;
}
for(int i=0;i<m;i++)
{
scanf("%d%d",&l,&r);
e[cnt]=r;
nt[cnt]=s[l];
s[l]=cnt++;
}
int tot=0;
for(int i=1;i<=n;i++)
{
for(int j=s[i];j!=-1;j=nt[j])
{
tot++;
build(1,1,n,e[j]);
}
if (tot<k) continue;
ans=max(ans,sum[getsum(1,1,n,k)]-sum[i-1]);
}
printf("%lld\n",ans);
}
return 0;
}