zoukankan      html  css  js  c++  java
  • 【bzoj1699/USACO2007】Balanced Lineup排队——RMQ问题

    题目链接

    很明显的求区间最大最小值问题,可以用st表做,不过ccz 大爷教我用zkw线段树来解决这种问题,感觉很好用><

    对于1~n的序列,我们先转化成0~n-1,(方便之后的xor),然后求一个最小的mx=(1<<i)使得mx>=n,这样就保证了是一棵满二叉树,叶子结点为0~mx-1。

    然后考虑对于每层建立一个数组tr[mx],拿最顶层来说,我们可以把它根据左右子树划分为0~mx/2-1,mx/2~mx-1,这样的话当i<=mx/2-1时,tr[i]即为i~mx/2-1的最大(小)值,当i>=mx/2,时,tr[i]即为mx/2~mx-1的最大(小)值(也就是左后缀,右前缀)。

    往下的每一层的数组都类似如此。

    当我们需要查询l~r时,现将l--,r--,然后我们要找到lca(l,r),这样的话最大(小)值就是max/min(tr[l],tr[r])。

    当然我们并不需要真的去用倍增求lca,仔细观察可以发现,当最底层为第0层的时候,它们的lca就在  l^r的二进制位数-1 那一层。

    不过这样的话查询仍是logn的,我们可以先预处理出0~1023的位数,1024~220 的位数我们可以通过log(a/b)=log(a)-log(b)求出。

    具体实现细节看代码:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 const int N=5e4+10;
     5 int a[N],tr[20][N],tr1[20][N];
     6 int wei[1024],ok[1024];
     7 int read(){
     8     int ans=0,f=1;char c=getchar();
     9     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    10     while(c>='0'&&c<='9'){ans=ans*10+c-48;c=getchar();}
    11     return ans*f;
    12 }
    13 int mx=1,h=0;
    14 /*-----------------------------------------------------*/
    15 void build(int l,int r,int x,int p){
    16     if(l==r){tr1[x][r]=tr[x][l]=a[l];return;}
    17     if(!p){
    18         tr1[x][r]=tr[x][r]=a[r];
    19         for(int i=r-1;i>=l;i--){
    20             tr[x][i]=std::max(a[i],tr[x][i+1]);
    21             tr1[x][i]=std::min(a[i],tr1[x][i+1]);
    22         }
    23     }
    24     else{
    25         tr1[x][l]=tr[x][l]=a[l];
    26         for(int i=l+1;i<=r;i++){
    27             tr[x][i]=std::max(a[i],tr[x][i-1]);
    28             tr1[x][i]=std::min(a[i],tr1[x][i-1]);
    29         }
    30     }
    31 }
    32 int main(){
    33     int n=read(),q=read(),ce=0;wei[0]=0;
    34     for(int i=0;i<=9;i++)ok[(1<<i)]=1;
    35     for(int i=1;i<=1023;i++)wei[i]=ok[i]?wei[i-1]+1:wei[i-1];
    36     do{mx*=2;}while(mx<n);
    37     for(int i=0;i<=n-1;i++){
    38         a[i]=read();
    39     }
    40     int ff;
    41     for(int i=1;i<=mx>>1;i<<=1){
    42         ff=0;
    43         for(int j=0;j<n;j+=i){
    44             build(j,j+i-1,ce,ff);
    45             ff^=1;
    46         }
    47         ce++;
    48     }
    49     while(q--){
    50         int l=read(),r=read();
    51         l--;r--;
    52         int x=l^r,p=0;
    53         if(x>=1024)p=wei[x/1024]+10;
    54         else p=wei[x];
    55         if(!p)printf("0
    ");
    56         else printf("%d
    ",std::max(tr[p-1][l],tr[p-1][r])-std::min(tr1[p-1][l],tr1[p-1][r])); 
    57     }
    58     return 0;
    59 }
    bzoj1699

     ccz 大爷的简洁版%%%:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 const int N=5e4+10;
     5 int a[N],tr[20][N][2];
     6 int wei[1024],ok[1024];
     7 int read(){
     8     int ans=0,f=1;char c=getchar();
     9     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    10     while(c>='0'&&c<='9'){ans=ans*10+c-48;c=getchar();}
    11     return ans*f;
    12 }
    13 int max(int a,int b){return a>b?a:b;}
    14 int min(int a,int b){return a<b?a:b;}
    15 int mx=1,h=0;
    16 /*-----------------------------------------------------*/
    17 int main(){
    18     int n=read(),q=read(),ce=0;wei[0]=0;
    19     for(int i=0;i<=9;i++)ok[(1<<i)]=1;
    20     for(int i=1;i<=1023;i++)wei[i]=ok[i]?wei[i-1]+1:wei[i-1];
    21     do mx*=2;while(mx<n);
    22     for(int i=0;i<=n-1;i++)a[i]=read();
    23     for(int i=1;i<mx;i<<=1){
    24         int(*f)[2]=tr[ce++];
    25         for(int j=i;j<n;j+=i<<1){
    26             f[j-1][0]=f[j-1][1]=a[j-1];
    27             f[j][0]=f[j][1]=a[j];
    28             for(int p=j+1;p<j+i;++p){
    29                 f[p][0]=min(f[p-1][0],a[p]);
    30                 f[p][1]=max(f[p-1][1],a[p]);
    31             }
    32             for(int p=j-2;p>=j-i;--p){
    33                 f[p][0]=min(f[p+1][0],a[p]);
    34                 f[p][1]=max(f[p+1][1],a[p]);
    35             }
    36         }
    37     }
    38     while(q--){
    39         int l=read(),r=read();
    40         l--;r--;
    41         int x=l^r,p=0;
    42         p=x>>10?wei[x>>10]+10:wei[x];
    43         if(!p)printf("0
    ");
    44         else printf("%d
    ",max(tr[p-1][l][1],tr[p-1][r][1])-min(tr[p-1][l][0],tr[p-1][r][0])); 
    45     }
    46     return 0;
    47 }
    48 
    ccz版
  • 相关阅读:
    Palindrome Partitioning
    Minimum Path Sum
    Maximum Depth of Binary Tree
    Minimum Depth of Binary Tree
    Unique Binary Search Trees II
    Unique Binary Search Trees
    Merge Intervals
    Merge Sorted Array
    Unique Paths II
    C++ Primer Plus 笔记第九章
  • 原文地址:https://www.cnblogs.com/JKAI/p/7500742.html
Copyright © 2011-2022 走看看