hdu-5700 区间交(二分+树状数组)
题目链接:
区间交
Problem Description
小A有一个含有n个非负整数的数列与mm个区间。每个区间可以表示为li,ri。
它想选择其中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)。
Output
一行表示答案
Sample Input
5 2 3 1 2 3 4 6 4 5 2 5 1 4
Sample Output
10
题意:
思路:
求相交区间和的最大值,首先是树状数组sum可以求log(n)求区间和,在找区间的时候枚举左端点,二分右端点,先把区间按左端点排序,然后一边更新一边询问,由于按左端点排序,所以左端点可以作为相交区间的左端点,二分右端点时询问这个点是否被大于等于k次覆盖,找到右端点最大的那个点,此时对应的区间就是这个左端点能得到的最大的区间,枚举完左端点就可以找到最大值了;
复杂度好像是mlog(n)log(n);
AC代码:
#include <bits/stdc++.h> /* #include <iostream> #include <queue> #include <cmath> #include <map> #include <cstring> #include <algorithm> #include <cstdio> */ using namespace std; #define Riep(n) for(int i=1;i<=n;i++) #define Riop(n) for(int i=0;i<n;i++) #define Rjep(n) for(int j=1;j<=n;j++) #define Rjop(n) for(int j=0;j<n;j++) #define mst(ss,b) memset(ss,b,sizeof(ss)); typedef long long LL; const LL mod=1e9+7; const double PI=acos(-1.0); const int inf=0x3f3f3f3f; const int N=1e5+4; int n,k,m; LL a[N]; LL sum[N]; int num[N]; struct node { int l,r; }po[N]; int cmp(node x,node y) { if(x.l==y.l)x.r>y.r; return x.l<y.l; } int lowbit(int x) { return x&(-x); } void update(int x,LL y) { while(x<=n) { sum[x]+=y; x+=lowbit(x); } } LL query(int pos) { LL ans=0; while(pos>0) { ans+=sum[pos]; pos-=lowbit(pos); } return ans; } void update1(int x,int flag) { while(x<=n) { num[x]+=flag; x+=lowbit(x); } } int query1(int x) { int ans=0; while(x>0) { ans+=num[x]; x-=lowbit(x); } return ans; } int check(int x) { if(query1(x)>=k)return 1; return 0; } int main() { while(scanf("%d%d%d",&n,&k,&m)!=EOF) { LL ans=0; mst(num,0); mst(sum,0); Riep(n)scanf("%lld",&a[i]),update(i,a[i]); Riep(m)scanf("%d%d",&po[i].l,&po[i].r); sort(po+1,po+m+1,cmp); for(int i=1;i<=m;i++) { update1(po[i].l,1); update1(po[i].r+1,-1); int L=po[i].l,R=po[i].r; while(L<=R) { int mid=(L+R)>>1; if(check(mid))L=mid+1; else R=mid-1; } LL fx=query(L-1),fy; if(po[i].l>1)fy=query(po[i].l-1); else fy=0; ans=max(ans,fx-fy); } printf("%lld\n",ans); } return 0; }