BZOJ2006: [NOI2010]超级钢琴

$n \leq 5e5$的正负数数列,求长度在$[L,R]$的区间和前$K \leq 5e5$大的区间和的和。

先把区间和变为两个前缀和相减。定一移二,确定区间右端点,然后左端点就是一个范围。用个堆把每个右端点能取得的区间和最大的那个丢进去,咋知道哪个最大?右端点前缀和一定,找左端点在一定范围内的最小:

方法一:如果打算用主席树,那就把三元组$(x,v,k)$丢进堆里,表示右端点为$x$,某个区间和为$v$,这个区间是$x$为右端点时对应范围的第$k$大的区间,每次取出时把$x$为右端点对应区间的第$k+1$大丢进堆里。

 1 //#include<iostream>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cstdio>
 5 #include<queue>
 6 //#include<time.h>
 7 //#include<complex>
 8 #include<algorithm>
 9 #include<stdlib.h>
10 using namespace std;
11 
12 int n,K,ll,rr;
13 #define maxn 500011
14 int sum[maxn],a[maxn];
15 
16 struct qnode{int id,v,k; bool operator < (const qnode &b) const {return v<b.v;}};
17 priority_queue<qnode> q;
18 
19 int root[maxn];
20 struct SMT
21 {
22     struct Node
23     {
24         int ls,rs;
25         int cnt;
26     }a[maxn*20];
27     int size,n;
28     void clear(int m) {n=m; size=0;}
29     void up(int x) {a[x].cnt=a[a[x].ls].cnt+a[a[x].rs].cnt;}
30     void insert(int &x,int y,int L,int R,int v)
31     {
32         x=++size; a[x].cnt=a[y].cnt+1;
33         if (L==R) {a[x].ls=a[x].rs=0; return;}
34         int mid=(L+R)>>1;
35         if (v<=mid) insert(a[x].ls,a[y].ls,L,mid,v),a[x].rs=a[y].rs;
36         else insert(a[x].rs,a[y].rs,mid+1,R,v),a[x].ls=a[y].ls;
37     }
38     void insert(int &x,int y,int v) {insert(x,y,1,n,v);}
39     int kth(int x,int y,int k)
40     {
41         if (k>a[y].cnt-a[x].cnt) return 0;
42         int L=1,R=n;
43         while (L<R)
44         {
45             int mid=(L+R)>>1;
46             if (a[a[y].ls].cnt-a[a[x].ls].cnt>=k) R=mid,x=a[x].ls,y=a[y].ls;
47             else k-=a[a[y].ls].cnt-a[a[x].ls].cnt,L=mid+1,x=a[x].rs,y=a[y].rs;
48         }
49         return L;
50     }
51 }t;
52 
53 #define LL long long
54 int lisa[maxn],li=0;
55 int main()
56 {
57     scanf("%d%d%d%d",&n,&K,&ll,&rr);
58     lisa[++li]=sum[0]; for (int i=1;i<=n;i++) scanf("%d",&a[i]),sum[i]=sum[i-1]+a[i],lisa[++li]=sum[i];
59     sort(lisa+1,lisa+1+li); li=unique(lisa+1,lisa+1+li)-lisa-1;
60     t.clear(li); t.insert(root[0],root[n+3],(sum[0]=lower_bound(lisa+1,lisa+1+li,sum[0])-lisa));
61     for (int i=1;i<=n;i++) t.insert(root[i],root[i-1],(sum[i]=lower_bound(lisa+1,lisa+1+li,sum[i])-lisa));
62     for (int i=ll;i<=n;i++) q.push((qnode){i,lisa[sum[i]]-lisa[t.kth(root[i-rr-1<0?n+3:i-rr-1],root[i-ll],1)],1});
63     
64     LL ans=0;
65     for (int i=1;i<=K;i++)
66     {
67         qnode now=q.top(); q.pop();
68         ans+=now.v;
69         int tmp;
70         if ((tmp=t.kth(root[now.id-rr-1<0?n+3:now.id-rr-1],root[now.id-ll],now.k+1))>0)
71             q.push((qnode){now.id,lisa[sum[now.id]]-lisa[tmp],now.k+1});
72     }
73     printf("%lld\n",ans);
74     return 0;
75 }
View Code

方法二:如果打算有st表,每次取掉堆中一个元素后,由于st表不支持删除,那就把那个区间以删除的点为界劈成两半再丢堆里,$(x,v,a,b,c)$表示右端点$x$,当前区间和$v$,是在$[a,b]$区间找到的左端点$c$。

 1 //#include<iostream>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cstdio>
 5 #include<queue>
 6 //#include<time.h>
 7 //#include<complex>
 8 #include<algorithm>
 9 #include<stdlib.h>
10 using namespace std;
11 
12 int n,K,ll,rr;
13 #define maxn 500011
14 int sum[maxn],a[maxn];
15 
16 struct qnode{int id,v,a,b,c; bool operator < (const qnode &b) const {return v<b.v;}};
17 priority_queue<qnode> q;
18 
19 int st[maxn][22],Log[maxn];
20 int query(int x,int y)
21 {
22     int l=Log[y-x+1];
23     return sum[st[x][l]]<sum[st[y-(1<<l)+1][l]]?st[x][l]:st[y-(1<<l)+1][l];
24 }
25 
26 #define LL long long
27 int main()
28 {
29     scanf("%d%d%d%d",&n,&K,&ll,&rr);
30     st[0][0]=0;
31     for (int i=1;i<=n;i++) scanf("%d",&a[i]),sum[i]=sum[i-1]+a[i],st[i][0]=i;
32     Log[0]=-1; for (int i=1;i<=n+1;i++) Log[i]=Log[i>>1]+1;
33     for (int j=1;j<=20;j++)
34         for (int i=0,to=(n-(1<<j)+1);i<=to;i++)
35             st[i][j]=sum[st[i][j-1]]<sum[st[i+(1<<(j-1))][j-1]]?st[i][j-1]:st[i+(1<<(j-1))][j-1];
36     for (int i=ll;i<=n;i++)
37     {
38         int tmp=query(max(0,i-rr),i-ll);
39         q.push((qnode){i,sum[i]-sum[tmp],max(0,i-rr),i-ll,tmp});
40     }
41     LL ans=0;
42     for (int i=1;i<=K;i++)
43     {
44         qnode now=q.top(); q.pop();
45         ans+=now.v;
46         int tmp;
47         if (now.c>now.a)
48         {
49             tmp=query(now.a,now.c-1);
50             q.push((qnode){now.id,sum[now.id]-sum[tmp],now.a,now.c-1,tmp});
51         }
52         if (now.c<now.b)
53         {
54             tmp=query(now.c+1,now.b);
55             q.push((qnode){now.id,sum[now.id]-sum[tmp],now.c+1,now.b,tmp});
56         }
57     }
58     printf("%lld\n",ans);
59     return 0;
60 }
View Code

 

posted @ 2018-03-14 16:40  Blue233333  阅读(168)  评论(0编辑  收藏  举报