此题求长度在l,r,之间内的区间的前k大之和
1.静态区间第k大,不就是主席树么!
可是不会写啊,以后填坑吧
2.优先队列
固定左端点,选取以此为起点的长度l<=x<=r的区间,固定此范围后寻找此范围内最大所到位置t;
由于左端点已经固定且每次i相同的操作下只将一个点放入优先队列,故不会出现重复;
注意:rmq维护的是最大的前缀和所在位置,返回的也是位置
#include<bits/stdc++.h> #define rep(i,x,y) for(register int i=x;i<=y;i++) #define ll long long using namespace std; const int N=500050; const int Logn=20; inline int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f;} namespace zjc{ int n,k,L,R,a[N],sum[N],f[N][Logn],lg[N];ll ans; struct node{int op,l,r,t; friend bool operator <(node x,node y){ return sum[x.t]-sum[x.op-1]<sum[y.t]-sum[y.op-1];} };priority_queue<node> q; void init(){ lg[0]=-1; rep(i,1,n) f[i][0]=i,lg[i]=lg[i>>1]+1; rep(j,1,Logn)for(int i=1;i+(1<<j)-1<=n;i++) f[i][j]=sum[f[i][j-1]]>sum[f[i+(1<<j-1)][j-1]]?f[i][j-1]:f[i+(1<<j-1)][j-1]; } int query(int x,int y){ int s=lg[y-x+1]; return sum[f[x][s]]>sum[f[y-(1<<s)+1][s]]?f[x][s]:f[y-(1<<s)+1][s]; } void work(){ n=read(),k=read(),L=read(),R=read(); rep(i,1,n) a[i]=read(),sum[i]=sum[i-1]+a[i]; init(); for(int i=1;i+L-1<=n;i++){ int l=i+L-1,r=min(i+R-1,n); int t=query(l,r); q.push((node){i,l,r,t}); } for(int i=1;i<=k;i++){ node u=q.top();q.pop(); ans+=sum[u.t]-sum[u.op-1]; if(u.l<=u.t-1) q.push((node){u.op,u.l,u.t-1,query(u.l,u.t-1)}); if(u.t+1<=u.r) q.push((node){u.op,u.t+1,u.r,query(u.t+1,u.r)}); } printf("%lld\n",ans);return; } } int main(){ freopen("seq.in","r",stdin); freopen("seq.out","w",stdout); zjc::work(); return 0; }