luogu2048 [NOI2010]超级钢琴 (优先队列+主席树)
思路:先扫一遍所有点作为右端点的情况,把它们能产生的最大值加到一个优先队列里,然后每次从优先队列里取出最大值,再把它对应的区间的次大值加到优先队列里,这样做K次
可以用一个前缀和,每次找i为右端点的第K大时,就相当于找[i-R,i-L](可能有±2的偏差,会意)的第K小值,然后把它减掉
这个可以用主席树来做
为了做起来方便,下标从2开始;离散化的话会稍微快一点
这个第K大也可以不用主席树来维护,而是每次找到那个最小值以后把这个区间从那个点拆成两部分,再把这两部分加到优先队列里
1 #include<bits/stdc++.h> 2 #define pa pair<int,int> 3 #define CLR(a,x) memset(a,x,sizeof(a)) 4 using namespace std; 5 typedef long long ll; 6 const int maxn=5e5+10,logn=20,inf=5e5+1; 7 8 inline ll rd(){ 9 ll x=0;char c=getchar();int neg=1; 10 while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();} 11 while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); 12 return x*neg; 13 } 14 15 int N,K,L,R; 16 int sum[maxn],tmp[maxn]; 17 int rot[maxn],pct,cnt[maxn*logn],ch[maxn*logn][2]; 18 int tim[maxn],ori[maxn]; 19 priority_queue<pa > q; 20 21 void insert(int pre,int &p,int l,int r,int x){ 22 p=++pct;cnt[p]=cnt[pre]+1; 23 if(l<r){ 24 int m=l+r>>1; 25 if(x<=m) ch[p][1]=ch[pre][1],insert(ch[pre][0],ch[p][0],l,m,x); 26 else ch[p][0]=ch[pre][0],insert(ch[pre][1],ch[p][1],m+1,r,x); 27 } 28 } 29 int query(int pre,int p,int l,int r,int k){ 30 if(k>cnt[p]-cnt[pre]) return -inf; 31 if(l==r) return l; 32 int w=cnt[ch[p][0]]-cnt[ch[pre][0]],m=l+r>>1; 33 if(k<=w) return query(ch[pre][0],ch[p][0],l,m,k); 34 else return query(ch[pre][1],ch[p][1],m+1,r,k-w); 35 } 36 37 int main(){ 38 //freopen("","r",stdin); 39 int i,j,k; 40 N=rd(),K=rd();L=rd(),R=rd(); 41 for(i=2;i<=N+1;i++) tmp[i]=sum[i]=sum[i-1]+rd(); 42 sort(tmp+1,tmp+N+2);int mm=unique(tmp+1,tmp+N+2)-tmp-1; 43 for(i=1;i<=N+1;i++){ 44 int x=lower_bound(tmp+1,tmp+mm+1,sum[i])-tmp; 45 ori[x]=sum[i];sum[i]=x; 46 // printf("%d %d\n",ori[x],sum[i]); 47 } 48 for(i=1;i<=N+1;i++){ 49 insert(rot[i-1],rot[i],0,inf,sum[i]); 50 // printf("%d\n",cnt[rot[i]]); 51 } 52 ll ans=0; 53 for(i=L+1;i<=N+1;i++){ 54 int x=query(rot[max(i-R-1,0)],rot[i-L],0,inf,tim[i]=1); 55 56 q.push(make_pair(ori[sum[i]]-ori[x],i)); 57 } 58 for(i=1;i<=K;i++){ 59 int p=q.top().second;ans+=q.top().first; 60 // printf("%d %d\n",p,ans); 61 q.pop();tim[p]++; 62 int x=query(rot[max(p-R-1,0)],rot[p-L],0,inf,tim[p]); 63 if(x==-inf) continue; 64 // printf("%d %d %d\n",p,tim[p],x); 65 q.push(make_pair(ori[sum[p]]-ori[x],p)); 66 } 67 printf("%lld\n",ans); 68 return 0; 69 }