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 }

 

posted @ 2018-10-09 10:04  Ressed  阅读(221)  评论(0编辑  收藏  举报