zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",ans);
    59     return 0;
    60 }
    View Code
  • 相关阅读:
    [转]django自定义表单提交
    [django/mysql] 使用distinct在mysql中查询多条不重复记录值的解决办法
    [Django]下拉表单与模型查询
    [Django]模型提高部分--聚合(group by)和条件表达式+数据库函数
    [Django]模型学习记录篇--基础
    [Django]数据批量导入
    怎么让自己的本地php网站让别人访问到
    HTML Marquee跑马灯
    marquee标签详解
    apache的虚拟域名rewrite配置以及.htaccess的使用。
  • 原文地址:https://www.cnblogs.com/Blue233333/p/8568489.html
Copyright © 2011-2022 走看看