[hdu 5700 区间交]树状数组+二分
知识点:data structure
binary index tree
1. 题目链接
[hdu 5700 区间交]
类似题目:[Codeforces 754D Fedor and coupons]这个题目思路一模一样,只需要对位置离散化一下^_^。
2. 题意描述
有
n
个非负整数
3. 解题思路
得到的区间交的左边界肯定是某一个区间的左边界,右边界肯定也是某一个区间的右边界。
对
m
个区间按照右端点降序排序。按照右端点的大小从大到小遍历每个右端点,假设当前遍历的右端点就是区间交的右端点,那么,左端点越靠左越好,所以就是要找到最靠左的第k个左端点。
这里可以用前缀和来记录向前有多少个左端点。用树状数组来维护前缀和。然后二分寻找前缀和为
注意结果可能爆long long.
4. 实现代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double LB;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
const int INF = 0x3f3f3f3f;
const LL INFL = 0x3f3f3f3f3f3f3f3fLL;
const LB eps = 1e-8;
const int MAXN = 100000 + 5;
int n, k, m;
LL pre[MAXN];
struct QNode {
int l, r, id;
bool operator < (const QNode& e) const {
if(r == e.r) return l < e.l;
return r > e.r;
}
} q[MAXN];
int c[MAXN];
inline int lowbit(int x) { return x & (-x); }
void update(int x, int v) {
while(x <= n) {
c[x] += v;
x += lowbit(x);
}
}
int query(int x) {
int ret = 0;
while(x > 0) {
ret += c[x];
x -= lowbit(x);
}
return ret;
}
int bsearch(int lb, int ub) {
while(lb <= ub) {
int mid = (lb + ub) >> 1;
if(query(mid) < k) lb = mid + 1;
else ub = mid - 1;
}
return lb;
}
inline LL sum(int lb, int ub) { return pre[ub] - pre[lb - 1]; }
int main() {
#ifdef ___LOCAL_WONZY___
freopen("input.txt", "r", stdin);
#endif // ___LOCAL_WONZY___
while(~scanf("%d %d %d", &n, &k, &m)) {
pre[0] = 0;
for(int i = 1, x; i <= n; ++i) scanf("%d", &x), pre[i] = pre[i - 1] + x;
for(int i = 1; i <= m; ++i) scanf("%d %d", &q[i].l, &q[i].r), q[i].id = i;
sort(q + 1, q + m + 1);
memset(c, 0, sizeof(c));
// 最靠右的k-1个右端点肯定不会是区间交
for(int i = 1; i <= k - 1; ++i) update(q[i].l, 1);
LL ans = 0;
for(int i = k; i <= m; ++i) {
update(q[i].l, 1);
int z = query(q[i].r);
if(z < k) continue;
int lb = bsearch(1, q[i].r);
if(ans < sum(lb, q[i].r)) ans = sum(lb, q[i].r);
}
printf("%I64d\n", ans);
}
return 0;
}