• 【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版
  • 相关阅读:
    WPF 快捷键读写txt
    win10 UWP GET Post
    win10 UWP GET Post
    win10 UWP Hmac
    win10 UWP Hmac
    win10 UWP MessageDialog 和 ContentDialog
    MySQL 触发器-更新字段时,status列会加一
    [SDOI2018]旧试题
    win10 UWP MessageDialog 和 ContentDialog
    win10 UWP RSS阅读器
  • 原文地址:https://www.cnblogs.com/JKAI/p/7500742.html
Copyright © 2020-2023  润新知