bzoj2006: [NOI2010]超级钢琴
st表。 st[i][j]表示[i,i+2^j-1]的最小的s的下标。
#include<cstdio> #include<algorithm> #include<cstring> #include<queue> using namespace std; const int maxn = 500000 + 10; int n,k,L,R; int s[maxn],st[maxn][20],log[maxn]; struct Status { int v,l,r,m,p; bool operator < (const Status b) const { return v < b.v; } Status(int V,int L,int R,int M,int P) { v = V; l = L; r=R; m=M; p=P; } }cur(0,0,0,0,0); priority_queue<Status> q; int query(int l,int r) { int p = log[r-l+1]; //printf("e %d %d %d %d %d\n",p,l,r,st[l][p],st[r-(1<<p)+1][p]); if(s[st[l][p]]<s[st[r-(1<<p)+1][p]]) return st[l][p]; else return st[r-(1<<p)+1][p]; } int main() { scanf("%d%d%d%d",&n,&k,&L,&R); for(int i=1,a;i<=n;i++) scanf("%d",&a),s[i]=s[i-1]+a; for(int i=2;i<=n;i++) log[i] = log[i-1] + ((i&-i)==i); for(int i=1;i<=n;i++) st[i][0]=i-1; for(int j=1,l=1;(l<<1)<=n;j++,l<<=1) for(int i=1;i+l+l-1<=n;i++) { if(s[st[i][j-1]] < s[st[i+l][j-1]]) st[i][j] = st[i][j-1]; else st[i][j] = st[i+l][j-1]; } for(int i=L,l,r,m;i<=n;i++) { l=max(1,i-R+1),r=i-L+1; m=query(l,r); q.push(Status(s[i]-s[m],l,r,m+1,i)); } long long res=0; for(int i=1,l,r,m;i<=k;i++) { cur=q.top(); q.pop(); res+=cur.v; if(cur.l<cur.m) { l=cur.l; r=cur.m-1; m=query(l,r); q.push(Status(s[cur.p]-s[m],l,r,m+1,cur.p)); //printf("t l=%d r=%d m=%d %d\n",l,r,m,s[cur.p]-s[m]); } if(cur.m<cur.r) { l=cur.m+1; r=cur.r; m=query(l,r); q.push(Status(s[cur.p]-s[m],l,r,m+1,cur.p)); //printf("t l=%d r=%d m=%d %d\n",l,r,m,s[cur.p]-s[m]); } } printf("%lld\n",res); return 0; }