枚举左端点,然后在线段树内,更新所有左边界小于当前点的区间的右端点,然后查线段树二分查第k大就好
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; const int N = 100005; LL a[N]; struct Node{ int l,r; bool operator<(const Node &rhs)const{ if(l==rhs.l)return r<rhs.r; return l<rhs.l; } }p[N]; int c[N<<2]; void add(int rt,int l,int r,int x){ ++c[rt]; if(l==r)return; int m=(l+r)>>1; if(x<=m)add(rt<<1,l,m,x); else add(rt<<1|1,m+1,r,x); } int ask(int rt,int l,int r,int k){ if(l==r)return l; int m=(l+r)>>1; if(c[rt<<1|1]>=k)ask(rt<<1|1,m+1,r,k); else ask(rt<<1,l,m,k-c[rt<<1|1]); } int main(){ int n,k,m; while(~scanf("%d%d%d",&n,&k,&m)){ for(int i=1;i<=n;++i){ LL x;scanf("%I64d",&x); a[i]=a[i-1]+x; } for(int i=1;i<=m;++i){ scanf("%d%d",&p[i].l,&p[i].r); } sort(p+1,p+1+m); memset(c,0,sizeof(c)); int cnt=1; LL res=0; for(int i=1;i<=m;++i){ for(;cnt<=m&&p[cnt].l<=p[i].l;++cnt) add(1,1,n,p[cnt].r); if(c[1]<k)continue; int cur=ask(1,1,n,k); if(cur>=p[i].l)res=max(res,a[cur]-a[p[i].l-1]); } printf("%I64d ",res); } return 0; }