题意:

【BZOJ2006】超级钢琴(RMQ,priority_queue)_三元组

思路:

用三元组(i, l, r)表示右端点为i,左端点在[l, r]之间和最大的区间([l, r]保证是对于i可行右端点区间的一个子区间),我们用堆维护一些这样的三元组。

堆中初始的元素为每个i,并且[l, r]为这个i可行左端点的区间。

假如某次最大值为(i, l, r),并且j为那个和最大区间的左端点,那么需要往堆中加入两个三元组(i, l, j-1)和(i, j+1, r)。

对于一个三元组,计算对应最大和的问题实际就是一个RMQ问题,可以通过Sparse Table在O(NlogN) – O(1)的时间内解决。

实际上固定左端点的方法也类似,程序中使用这种方法

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cmath>
 5 #include<queue>
 6 #include<iostream>
 7 #include<algorithm>
 8 #include<set>
 9 #include<map>
10 #define mp(a,b,c,d) (data){a,b,c,d}
11 #define inf 1000000000
12 #define ll long long
13 #define MAXN 510000
14 using namespace std;
15 struct data{int i,l,r,t;};
16 
17 int f[MAXN][20];
18 int a[MAXN];
19 
20 int query(int x,int y)
21 {
22     if(x>y) return 0;
23     int len=y-x+1; int l=log(len)/log(2);
24     int s1=f[x][l];
25     int s2=f[y-(1<<l)+1][l];
26     if(a[s1]>a[s2]) return s1;
27      else return s2;
28 }
29 
30 bool operator<(data x,data y)
31 {
32     return a[x.t]-a[x.i-1]<a[y.t]-a[y.i-1];
33 }
34 
35 int main()
36 {
37     freopen("bzoj2006.in","r",stdin);
38     freopen("bzoj2006.out","w",stdout);
39     priority_queue<data,vector<data> >q;
40     int n,K,L,R;
41     scanf("%d%d%d%d",&n,&K,&L,&R);
42     for(int i=1;i<=n;i++) 
43     {
44         scanf("%d",&a[i]);
45         a[i]+=a[i-1];
46         f[i][0]=i;
47     }
48     int l=log(n)/log(2);
49     for(int i=1;i<=l;i++)
50      for(int j=1;j+(1<<i)-1<=n;j++) 
51      {
52          int x=f[j][i-1]; int y=f[j+(1<<(i-1))][i-1];
53          if(a[x]>a[y]) f[j][i]=x;
54           else f[j][i]=y;
55      }
56     for(int i=1;i<=n;i++)
57      if(i+L-1<=n)
58      {
59          int t=min(n,i+R-1);
60          q.push(mp(i,i+L-1,t,query(i+L-1,t)));
61      }
62     ll ans=0;
63     for(int i=1;i<=K;i++)
64     {
65         data t=q.top();q.pop();
66         ans+=a[t.t]-a[t.i-1];
67         //printf("%lld\n",ans);
68         if(t.t-1>=t.l) q.push(mp(t.i,t.l,t.t-1,query(t.l,t.t-1)));
69         if(t.t+1<=t.r) q.push(mp(t.i,t.t+1,t.r,query(t.t+1,t.r)));
70     }
71     printf("%lld\n",ans);
72     return 0;
73 }