http://acm.hdu.edu.cn/showproblem.php?pid=5700
这是这次百度之星初赛2B的第五题。省赛回来看了一下,有这样一个思路:对于所有的区间排序,按左值排序。
然后枚举区间左值lt,计算区间右值rt最大是多少,并且满足与至少k个区间相交。关键是解决与k个区间相交这个关系。首先区间左值大于lt的是不考虑的,因为这样相交区间的左值就不是lt了。也就是考虑区间左值小于等于lt的区间中,与rt区间至少有k个相交的区间。也就是在前面的条件下,计算是否有至少k个区间右值大于等于rt。
于是,依次枚举区间,将区间右值加入树状数组。二分rt的位置,判断query(rt, n)在树状数组中的和是否大于k即可。
代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <algorithm> #include <set> #include <map> #include <queue> #include <vector> #include <string> #define LL long long using namespace std; const int maxN = 100005; int n, k, m; LL s[maxN]; struct node { int lt, rt; bool operator<(node x) const { if (lt != x.lt) return lt < x.lt; else return rt < x.rt; } }p[maxN]; int d[maxN]; int lowbit(int x) { return x&(-x); } void add(int id,int pls) { while(id <= maxN)//id最大是maxN { d[id] += pls; id += lowbit(id); } } int sum(int to) { int s = 0; while(to > 0) { s = s + d[to]; to -= lowbit(to); } return s; } int query(int from, int to) { return sum(to) - sum(from-1); } void input() { int t; s[0] = 0; for (int i = 1; i <= n; ++i) { scanf("%d", &t); s[i] = s[i-1]+t; } } int cal(int lt) { int rt = n, mid; while (lt+1 < rt) { mid = (lt+rt)>>1; if (query(mid, n) >= k) lt = mid; else rt = mid; } if (query(rt, n) >= k) return rt; else if (query(lt, n) >= k) return lt; else return -1; } void work() { for (int i = 0; i < m; ++i) scanf("%d%d", &p[i].lt, &p[i].rt); sort(p, p+m); memset(d, 0, sizeof(d)); LL ans = 0; int to; for (int i = 0; i < m; ++i) { add(p[i].rt, 1); to = cal(p[i].lt); if (to != -1) ans = max(ans, s[to]-s[p[i].lt-1]); } printf("%lld ", ans); } int main() { //freopen("test.in", "r", stdin); //freopen("test.out", "w", stdout); while (scanf("%d%d%d", &n, &k, &m) != EOF) { input(); work(); } return 0; }