首页 > 代码库 > [NOI2010]超级钢琴 划分树+堆
[NOI2010]超级钢琴 划分树+堆
#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<queue>using namespace std;#define N 510000struct P{ int x,y; P(int a=0,int b=0){x=a,y=b;} bool operator<(P a)const{ return y<a.y; } };int val[N][23],num[N][23],ci[N];int s[N];int n,k,L,R;void build(int h,int L,int R){ if(L==R)return; int mid=(L+R)/2,left=L,right=mid+1,same=mid-L+1; for(int i=L;i<=R;i++)if(val[i][h]<s[mid])same--; for(int i=L;i<=R;i++){ if(val[i][h]<s[mid])val[left++][h+1]=val[i][h]; else if(val[i][h]==s[mid]&&same){ val[left++][h+1]=val[i][h]; --same; }else{ val[right++][h+1]=val[i][h]; } num[i][h]=num[L-1][h]+left-L; } build(h+1,L,mid); build(h+1,mid+1,R);}int kth(int h,int L,int R,int x,int y,int k){ if(L==R)return val[L][h]; int mid=(L+R)/2,left=num[y][h]-num[x-1][h]; int pre=num[x-1][h]-num[L-1][h]; if(left>=k)return kth(h+1,L,mid,L+pre,L+pre+left-1,k); else{ k-=left; pre=x-L-pre; left=y-x+1-left; return kth(h+1,mid+1,R,mid+pre+1,mid+pre+left,k); } }int Kth(int x,int y,int k){ return kth(1,1,n,x,y,k); }priority_queue<P> jj;int l[N],r[N];long long ans;int main(){ scanf("%d%d%d%d",&n,&k,&L,&R); for(int i=1;i<=n;i++){ int a; scanf("%d",&a); s[i]=s[i-1]+a; } for(int i=1;i<=n;i++)val[i][1]=s[i]; sort(s+1,s+n+1); build(1,1,n); for(int i=1;i<=n-L+1;i++){ l[i]=i+L-1; r[i]=min(n,i+R-1); jj.push(P(i,Kth(l[i],r[i],r[i]-l[i]+1)-val[i-1][1])); } for(int i=1;i<=k;i++){ P x=jj.top(); jj.pop(); ans+=x.y; if(r[x.x]-l[x.x]>ci[x.x]){jj.push(P(x.x,Kth(l[x.x],r[x.x],r[x.x]-l[x.x]-ci[x.x])-val[x.x-1][1])); ci[x.x]++; } } cout<<ans;}
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。