zoukankan      html  css  js  c++  java
  • bzoj4540: [Hnoi2016]序列

    Description

      给定长度为n的序列:a1,a2,…,an,记为a[1:n]。类似地,a[l:r](1≤l≤r≤N)是指序列:al,al+1,…,ar-
    1
    ,ar。若1≤l≤s≤t≤r≤n,则称a[s:t]是a[l:r]的子序列。现在有q个询问,每个询问给定两个数l和r,1≤l≤r
    ≤n,求a[l:r]的不同子序列的最小值之和。例如,给定序列5,2,4,1,3,询问给定的两个数为1和3,那么a[1:3]有
    6个子序列a[1:1],a[2:2],a[3:3],a[1:2],a[2:3],a[1:3],这6个子序列的最小值之和为5+2+4+2+2+2=17。

    Input

      输入文件的第一行包含两个整数n和q,分别代表序列长度和询问数。接下来一行,包含n个整数,以空格隔开
    ,第i个整数为ai,即序列第i个元素的值。接下来q行,每行包含两个整数l和r,代表一次询问。

    Output

      对于每次询问,输出一行,代表询问的答案。

    Sample Input

    5 5
    5 2 4 1 3
    1 5
    1 3
    2 4
    3 5
    2 5

    Sample Output

    28
    17
    11
    11
    17

    HINT

    1 ≤N,Q ≤ 100000,|Ai| ≤ 10^9

    题解:
    此题有很多做法
    1.第一种很naive,就是从n2暴力优化过来,但会被卡常数
    设ans[i][j]表示i到j的最小值是多少,询问就是∑ans[i][j] (l<=i<=j<=r),做个二位前缀和即可
    设最小的x满足在区间[ x , i ]中,a[i]是最小值(不严格,即在这个区间中可以有和a[i]相等的数),记作L[i]
    设最大的y满足在区间[ i , y ]中,a[i]是最小值(严格,即在这个区间中不可以有和a[i]相等的数),记作R[i]
    显然L[i]和R[i]都是可以用单调栈搞出来的
    对于样例的ans数组如下
    1 1 1 1 3
    1 1 1 1
    2 2 4
    2 2
    5
    我们发现对于一个a[i],显然对于任意一个x和y,如果满足L[i]<=x<=i && i<=y<=R[i],那么ans[x][y]=a[i]
    这显然是个矩形区域,而且询问也是,所以这可以用四分树做,复杂度为O( n log2 n ),但常数大,最慢的点要跑7s,所以不能通过此题……
    2.第二种来源于claris另一道题的题解:http://www.cnblogs.com/clrs97/p/4824806.html
    先将问题离线化,按右端点排序
    我们发现上面那个ans数组每一行可以看成将上一行进行一次区间覆盖操作
    而询问(l,r)的答案就是在第r行时,历史上所有sum[ l , r ]的和
    通过线段树打标记维护,时间复杂度O( n log n )。
    对于线段树上每个节点,维护以下信息: 
    v : 当前区间内所有数的和
    s : 历史上所有v的和    
    l : 区间长度   
    a,b,c,d : 标记,分别表示生效之后   
    v'=a*v+b*l  
    s'=c*v+d*l+s  
    3.第三种是莫队算法  
    考虑假如已经知道了[ l , r ]的答案,将它减去所有左端点在 l 右端点在[ l , r ]的区间的最小值,就可以得到[ l + 1 , r ]的答案 
    显然右端点在 i 到 R[i] 的贡献为a[i] ,在R[i] + 1 到 R[ R[i] + 1 ] 的贡献为a[ R[i] + 1 ],... 
    以此类推,直到某个 p 的 R[p] + 1 > r ,剩下 p 到 r 的贡献为a[p]  
    暴力跳R[i]显然会T,我们发现,假如说定义a[ n + 1 ] = -inf 则每个点的下一个点都是确定的,这个形成了一个树形关系  
    我们将一个点 i 的父亲定义为R[i] + 1,与父亲连的边的边权为 a[i] * ( R[i] - i + 1 )  
    那么转移的时候先求出[ l , r ]中的最小值的位置p,答案将减去 dis[l] - dis[p] + a[p] * ( r - p + 1 )   
    其他转移类似   
    code:   
    第一种TLE:
     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<cstring>
     5 #include<algorithm>
     6 using namespace std;
     7 typedef long long int64;
     8 char ch;
     9 bool ok;
    10 void read(int &x){
    11     ok=0;
    12     for (ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1;
    13     for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
    14     if (ok) x=-x;
    15 }
    16 const int inf=2147483647;
    17 const int maxn=100005;
    18 int n,q,a[maxn],x,y,l[maxn],r[maxn],top,stack[maxn];
    19 struct segx{
    20     int tot,root,son[16000000][4];
    21     int64 sum[16000000],tag[16000000];
    22     void init(){tot=root=1;}
    23     void cover(int &k,int l1,int r1,int x1,int x2,int l2,int r2,int y1,int y2,int v){
    24         if (!k) k=++tot;
    25         if (x1<=l1&&r1<=x2&&y1<=l2&&r2<=y2){tag[k]+=v,sum[k]+=1LL*v*(r1-l1+1)*(r2-l2+1);return;}
    26         int m1=(l1+r1)>>1,m2=(l2+r2)>>1;
    27         if (x1<=m1&&y1<=m2) cover(son[k][0],l1,m1,x1,x2,l2,m2,y1,y2,v);
    28         if (x1<=m1&&m2<y2) cover(son[k][2],l1,m1,x1,x2,m2+1,r2,y1,y2,v);
    29         if (m1<x2&&y1<=m2) cover(son[k][1],m1+1,r1,x1,x2,l2,m2,y1,y2,v);
    30         if (m1<x2&&m2<y2) cover(son[k][3],m1+1,r1,x1,x2,m2+1,r2,y1,y2,v);
    31         sum[k]=0;
    32         for (int i=0;i<4;i++) sum[k]+=sum[son[k][i]];
    33     }
    34     void cover(int x1,int x2,int y1,int y2,int v){cover(root,1,n,x1,x2,1,n,y1,y2,v);}
    35     int64 query(int k,int l1,int r1,int x1,int x2,int l2,int r2,int y1,int y2,int64 t){
    36         if (!k) return t*(min(r1,x2)-max(l1,x1)+1)*(min(r2,y2)-max(l2,y1)+1);
    37         if (x1<=l1&&r1<=x2&&y1<=l2&&r2<=y2) return sum[k]+t*(r1-l1+1)*(r2-l2+1);
    38         int m1=(l1+r1)>>1,m2=(l2+r2)>>1;
    39         int64 res=0;
    40         if (x1<=m1&&y1<=m2) res+=query(son[k][0],l1,m1,x1,x2,l2,m2,y1,y2,t+tag[k]);
    41         if (x1<=m1&&m2<y2) res+=query(son[k][2],l1,m1,x1,x2,m2+1,r2,y1,y2,t+tag[k]);
    42         if (m1<x2&&y1<=m2) res+=query(son[k][1],m1+1,r1,x1,x2,l2,m2,y1,y2,t+tag[k]);
    43         if (m1<x2&&m2<y2) res+=query(son[k][3],m1+1,r1,x1,x2,m2+1,r2,y1,y2,t+tag[k]);
    44         return res;
    45     }
    46     int64 query(int x1,int x2,int y1,int y2){return query(root,1,n,x1,x2,1,n,y1,y2,0);}
    47 }Tx;
    48 int main(){
    49     read(n),read(q),Tx.init();
    50     for (int i=1;i<=n;i++) read(a[i]);
    51     a[0]=a[n+1]=-inf;
    52     stack[top=1]=0;
    53     for (int i=1;i<=n;i++){
    54         while (top&&a[stack[top]]>=a[i]) top--;
    55         l[i]=stack[top]+1;
    56         stack[++top]=i;
    57     }
    58     stack[top=1]=n+1;
    59     for (int i=n;i>=1;i--){
    60         while (top&&a[stack[top]]>a[i]) top--;
    61         r[i]=stack[top]-1;
    62         stack[++top]=i;
    63     }
    64     for (int i=1;i<=n;i++) Tx.cover(l[i],i,i,r[i],a[i]);
    65     while (q--) read(x),read(y),printf("%lld
    ",Tx.query(x,y,x,y));
    66     return 0;
    67 }

    第二种:

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<cstring>
     5 #include<algorithm>
     6 using namespace std;
     7 typedef long long int64;
     8 char ch;
     9 bool ok;
    10 void read(int &x){
    11     for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1;
    12     for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
    13     if (ok) x=-x;
    14 }
    15 const int maxn=100005;
    16 const int inf=2147483647;
    17 int n,q,a[maxn],stack[maxn],top;
    18 int64 ans[maxn];
    19 struct Quer{
    20     int l,r,id;
    21     void init(int i){read(l),read(r),id=i;}
    22 }quer[maxn];
    23 bool cmp(const Quer &a,const Quer &b){return a.r<b.r;}
    24 struct Data{
    25     int64 a,b,c,d;
    26     void init(){a=1,b=c=d=0;}
    27 };
    28 Data operator+(const Data &x,const Data &y){return (Data){x.a*y.a,x.b*y.a+y.b,y.c*x.a+x.c,y.c*x.b+x.d+y.d};}
    29 struct Seg{
    30     #define ls k<<1
    31     #define rs (k<<1)+1
    32     int len[maxn<<2];
    33     int64 v[maxn<<2],s[maxn<<2];
    34     Data tag[maxn<<2];
    35     void addtag(int k,Data t){s[k]=t.c*v[k]+t.d*len[k]+s[k],v[k]=t.a*v[k]+t.b*len[k],tag[k]=tag[k]+t;}
    36     void pushdown(int k){addtag(ls,tag[k]),addtag(rs,tag[k]),tag[k].init();}
    37     void update(int k){v[k]=v[ls]+v[rs],s[k]=s[ls]+s[rs];}
    38     void build(int k,int l,int r){
    39         tag[k].init(),len[k]=r-l+1;
    40         if (l==r) return;
    41         int m=(l+r)>>1;
    42         build(ls,l,m),build(rs,m+1,r);
    43     }
    44     void cover(int k,int l,int r,int x,int y,Data t){
    45         if (l==x&&r==y){addtag(k,t);return;}
    46         int m=(l+r)>>1; pushdown(k);
    47         if (y<=m) cover(ls,l,m,x,y,t);
    48         else if (x<=m) cover(ls,l,m,x,m,t),cover(rs,m+1,r,m+1,y,t);
    49         else cover(rs,m+1,r,x,y,t);
    50         update(k);
    51     }
    52     void cover(int x,int y,int v){cover(1,1,n,x,y,(Data){0,v,0,0}),addtag(1,(Data){1,0,1,0});}
    53     int64 query(int k,int l,int r,int x,int y){
    54         if (l==x&&r==y) return s[k];
    55         int m=(l+r)>>1; pushdown(k);
    56         if (y<=m) return query(ls,l,m,x,y);
    57         else if (x<=m) return query(ls,l,m,x,m)+query(rs,m+1,r,m+1,y);
    58         else return query(rs,m+1,r,x,y);
    59     }
    60     int64 query(int x,int y){return query(1,1,n,x,y);}
    61 }T;
    62 int main(){
    63     read(n),read(q),a[0]=-inf,T.build(1,1,n);
    64     for (int i=1;i<=n;i++) read(a[i]);
    65     for (int i=1;i<=q;i++) quer[i].init(i);
    66     sort(quer+1,quer+q+1,cmp);
    67     stack[top=1]=0;
    68     for (int i=1,j=1;i<=n;i++){
    69         while (top&&a[stack[top]]>=a[i]) top--;
    70         T.cover(stack[top]+1,i,a[i]);
    71         for (;quer[j].r==i;j++) ans[quer[j].id]=T.query(quer[j].l,quer[j].r);
    72         stack[++top]=i;
    73     }
    74     for (int i=1;i<=q;i++) printf("%lld
    ",ans[i]);
    75     return 0;
    76 }

    第三种:

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<cstring>
     5 #include<algorithm>
     6 #include<cassert>
     7 using namespace std;
     8 typedef long long int64;
     9 char ch;
    10 bool ok;
    11 void read(int &x){
    12     ok=0;
    13     for (ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1;
    14     for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
    15     if (ok) x=-x;
    16 }
    17 const int inf=2147483647;
    18 const int maxn=100005;
    19 const int maxm=maxn;
    20 int n,q,a[maxn],x,y,l[maxn],r[maxn],top,stack[maxn],pos[maxn];
    21 struct Graph{
    22     int tot,now[maxn],son[maxm],pre[maxm];
    23     int64 val[maxm],dis[maxn];
    24     void put(int a,int b,int64 c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;}
    25     void dfs(int u){for (int p=now[u],v=son[p];p;p=pre[p],v=son[p]) dis[v]=dis[u]+val[p],dfs(v);}
    26 }G[2];
    27 int st[maxn][17],sn,bel[maxn];
    28 int64 ans[maxn],res;
    29 struct Queries{
    30     int l,r,id;
    31     void init(int i){read(l),read(r),id=i;}
    32 }queries[maxn];
    33 bool cmp(const Queries &a,const Queries &b){return bel[a.l]<bel[b.l]||(bel[a.l]==bel[b.l]&&bel[a.r]<bel[b.r]);}
    34 int get_min(int i,int j){return a[i]<a[j]?i:j;}
    35 int calc(int x,int y){
    36     if (x>y) swap(x,y);
    37     int step=pos[y-x+1];
    38     return get_min(st[x][step],st[y-(1<<step)+1][step]);
    39 }
    40 void movel(int x,int y,int op){
    41     int p=calc(x,y);
    42     int64 tmp=G[1].dis[x]-G[1].dis[p]+1LL*a[p]*(y-p+1);
    43     res+=op*tmp;
    44 }
    45 void mover(int x,int y,int op){
    46     int p=calc(x,y);
    47     int64 tmp=G[0].dis[y]-G[0].dis[p]+1LL*a[p]*(p-x+1);
    48     res+=op*tmp;
    49 }
    50 void work(){
    51     int l=1,r=1; res=a[1];
    52     for (int i=1;i<=q;i++){
    53         for (;r<queries[i].r;r++) mover(l,r+1,1);
    54         for (;l>queries[i].l;l--) movel(l-1,r,1);
    55         for (;r>queries[i].r;r--) mover(l,r,-1);
    56         for (;l<queries[i].l;l++) movel(l,r,-1);
    57         ans[queries[i].id]=res;
    58     }
    59     for (int i=1;i<=q;i++) printf("%lld
    ",ans[i]);
    60 }
    61 int main(){
    62     read(n),read(q),sn=sqrt(n),pos[0]=-1;
    63     for (int i=1;i<=n;i++) bel[i]=i/sn;
    64     for (int i=1;i<=n;i++) pos[i]=pos[i>>1]+1;
    65     for (int i=1;i<=n;i++) read(a[i]);
    66     for (int i=1;i<=n;i++) st[i][0]=i;
    67     for (int j=1;j<=17;j++) for (int i=1;i<=n;i++){
    68         st[i][j]=st[i][j-1];
    69         if (i+(1<<(j-1))<=n) st[i][j]=get_min(st[i][j],st[i+(1<<(j-1))][j-1]);
    70     }
    71     a[0]=a[n+1]=-inf;
    72     stack[top=1]=0;
    73     for (int i=1;i<=n;i++){
    74         while (top&&a[stack[top]]>=a[i]) top--;
    75         G[0].put(stack[top],i,1LL*(i-stack[top])*a[i]);
    76         stack[++top]=i;
    77     }
    78     stack[top=1]=n+1;
    79     for (int i=n;i>=1;i--){
    80         while (top&&a[stack[top]]>a[i]) top--;
    81         G[1].put(stack[top],i,1LL*(stack[top]-i)*a[i]);
    82         stack[++top]=i;
    83     }
    84     G[0].dfs(0),G[1].dfs(n+1);
    85     for (int i=1;i<=q;i++) queries[i].init(i);
    86     sort(queries+1,queries+q+1,cmp);
    87     work();
    88     return 0;
    89 }
  • 相关阅读:
    网络性能测试工具iperf详解
    linux下的抓包工具tshark和 tcpdump用法
    linux下网络发包工具
    >/dev/null 2>&1 的作用
    linux screen 命令详解
    wget 命令操作实例
    Centos Linux release 7.2.15ll (core) yum 安装java环境
    日志监听
    java 身份证工具类
    java 生成微信的二维码 工具类
  • 原文地址:https://www.cnblogs.com/chenyushuo/p/5422933.html
Copyright © 2011-2022 走看看