区间交
算法,百度2016-06-04
5 2 3 1 2 3 4 6 4 5 2 5 1 4
10
题解:
题目要求从m个区间中找出k个区间的交区间,且交区间的sum(a[l],a[r])的和最大. 我们可以考虑转换这个问题.变为求原序列的一段区间被多少个区间覆盖.
假设当前找的是区间[L,R],那么很显然某个区间要包含这个[L,R],它的左右端点必须要L,R的两边. 知道这个,我们只需要处理那些左端点<=L的.然后再通过树状
数组求出有多少个右端点>=R.然后对于原序列的区间,只需要尺取一下就行了.
AC代码:
#include <iostream> #include <string.h> #include <map> #include <set> #include <stack> #include <vector> #include <stdio.h> #include <algorithm> using namespace std; typedef long long ll; const int N = 1e5 + 10; int a[N],c[N]; struct Interval { int l,r; void read() { scanf("%d %d",&l,&r); } bool operator < (const Interval &a) const { return l < a.l; } } interval[N]; void add(int x,int n) { while(x <= n) { c[x]++; x += x & -x; } } int get(int x) { int s = 0; x--; while(x > 0) { s += c[x]; x -= x & -x; } return s; } void solve() { int n,k,m; while(~scanf("%d %d %d",&n,&k,&m)) { memset(c,0,sizeof c); for(int i = 1; i <= n; ++i) scanf("%d",&a[i]); for(int i = 1; i <= m; ++i) interval[i].read(); sort(interval + 1,interval + m + 1); ll ans = 0,sum = 0; int l,pos; pos = l = 1; for(int r = 1; r <= n; ++r) { sum += a[r]; while(l <= r) { while(pos <= m && interval[pos].l <= l) add(interval[pos++].r,n); int num = pos - 1 - get(r); if(num >= k) { ans = max(ans,sum); break; } else { sum -= a[l]; l++; } } } cout << ans << endl; } } int main() { solve(); return 0; }