小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
一行表示答案
Input示例
5 2 3 1 2 3 4 6 4 5 2 5 1 4
Output示例
10
Joe
(题目提供者)
分析:
想明白以后确实是不难的,就是前期想着不好想。为了证明自己真的是理解了,把数据按左端点排序自己拍了一遍。
解释一下这个题:
我们首先把左端点从小到大排序(掌握以后,这个排序不论是排右端点、从大到小都可以做的),然后我们依次枚举左端点,我们把当前枚举的左端点 l 当做区间交的左端点,那么很明显,其他的区间的左端点肯定是要小于 l ,那么也就是说,前 k - 1 个端点不用枚举。
接下来就是数据的处理了,我们枚举了左端点,然后找右端点的时候要尽量靠右,这个右端点该怎么找呢?我们用一个线段树记录右端点,当我们枚举第 x 个区间的时候,后面的区间的右端点都是干扰的,我们就先不让它加入线段树,当然,前面的端点都要在线段树里(当时是这一点没想到),然后在这些端点中找最靠右的右端点,然后算前缀和更新一下ans。
然后我们要处理 x+1 区间了,我们把 x+1 的右端点加入线段数,重复前面的操作即可。
#include
#include
#include
#include
#define MAXN 100005
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
LL sum[MAXN + 5];
struct Node { int st,ed; }a[MAXN + 5];
struct Seg_Ment_Tree{ int l,r,sum; }tre[MAXN << 2];
inline bool cmp(Node a,Node b ) { return a.st < b.st; }
void Build(int u,int l,int r) {
tre[u].l = l,tre[u].r = r;
if(l == r){ tre[u].sum = 0; return ; }
int Mid = l + r >> 1;
Build(u<<1,l,Mid); Build(u<<1|1,Mid + 1,r);
tre[u].sum = tre[u<<1].sum + tre[u<<1|1].sum;
}
void Modify(int u,int pos) {
if(tre[u].l == tre[u].r) { tre[u].sum ++; return; }
int Mid = tre[u].l + tre[u].r >> 1;
if(pos <= Mid) Modify(u<<1,pos);
else Modify(u<<1|1,pos);
tre[u].sum = tre[u<<1|1].sum + tre[u<<1].sum;
}
int Query(int u,int x) {
if(tre[u].l == tre[u].r) return tre[u].l;
if(tre[u<<1|1].sum >= x) return Query(u<<1|1,x);
else return Query(u<<1,x - tre[u<<1|1].sum);
}
int main(int argc,char *argv[]) {
int n,k,m,t;
scanf("%d %d %d",&n, &k, &m);
sum[0] = 0;
for(int i=1; i<=n; ++i) {
scanf("%d",&t);
sum[i] = sum[i-1] + t;
}
for(int i=1; i<=m; ++i) scanf("%d %d",&a[i].st,&a[i].ed);
sort(a + 1, a + m + 1,cmp);
Build(1,1,n);
for(int i=1; i<=k; ++i)
Modify(1,a[i].ed);
LL Ans = 0;
a[m + 1].ed = 1;
for(int i=k; i<=m; ++i) {
LL pos = Query(1,k);
if(pos >= a[i].st) Ans = max(Ans,sum[pos] - sum[a[i].st - 1]);
Modify(1,a[i + 1].ed);
}
printf("%I64d\n",Ans);
return 0;
}