• BZOJ 2653: middle 主席树 二分


    https://www.lydsy.com/JudgeOnline/problem.php?id=2653

    因为是两个方向向外延伸所以不能对编号取前缀和(这里只有前缀和向后传递的性质,不是实际意义的和),那么对排序后的数字取前缀和,线段树维护编号然后二分就可以了。

    在一个值相对的线段树中,数小于该值的位置视为-1,数大于等于该值的位置视为+1. 那么当可取的区间内可以的到的最大的和>=0时该数就是合法的。

    维护lmx, rmx, sum三个值分别表示该区间从左向右能得到的最大前缀和、从右向左能得到的最大前缀和、区间和。

    二分到区间没有的数也没有关系,二分终究会收敛到区间中存在的数。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<cmath>
     6 using namespace std;
     7 #define LL long long
     8 #define pa pair<int,int>
     9 const int maxn=20010;
    10 pa a[maxn];
    11 int n,m;
    12 int q[5]={};
    13 int rt[maxn]={};
    14 int siz[maxn*20]={},lmx[maxn*20]={},rmx[maxn*20]={},lc[maxn*20]={},rc[maxn*20]={},tot=0;
    15 inline void updata(int x){
    16     siz[x]=siz[lc[x]]+siz[rc[x]];
    17     lmx[x]=max(lmx[lc[x]],siz[lc[x]]+lmx[rc[x]]);
    18     rmx[x]=max(rmx[rc[x]],siz[rc[x]]+rmx[lc[x]]);
    19 }
    20 void build(int &x,int l,int r){
    21     x=++tot; siz[x]=lmx[x]=rmx[x]=(r-l+1);
    22     if(l==r)return;
    23     int mid=(l+r)/2;
    24     build(lc[x],l,mid);
    25     build(rc[x],mid+1,r);
    26 }
    27 void inser(int &x,int y,int l,int r,int z){
    28     x=++tot;siz[x]=siz[y];lmx[x]=lmx[y];rmx[x]=rmx[y];lc[x]=lc[y];rc[x]=rc[y];
    29     if(l==r){siz[x]=-1;lmx[x]=0;rmx[x]=0;return;}
    30     int mid=(l+r)/2;
    31     if(z<=mid) inser(lc[x],lc[y],l,mid,z);
    32     else inser(rc[x],rc[y],mid+1,r,z);
    33     updata(x);
    34 }
    35 int getsum(int x,int l,int r,int zl,int zr){
    36     if(zl>zr)return 0;
    37     if(zl<=l&&r<=zr){return siz[x];}
    38     int mid=(l+r)/2,ans=0;
    39     if(zl<=mid)ans=getsum(lc[x],l,mid,zl,zr);
    40     if(mid<zr)ans+=getsum(rc[x],mid+1,r,zl,zr);
    41     return ans;
    42 }
    43 int getl(int x,int l,int r,int zl,int zr){
    44     if(zl>zr)return 0;
    45     if(zl<=l&&r<=zr)return lmx[x];
    46     int mid=(l+r)/2,ans=0;
    47     if(zl<=mid)ans=getl(lc[x],l,mid,zl,zr);
    48     if(mid<zr)ans=max(ans,getl(rc[x],mid+1,r,zl,zr)+getsum(lc[x],l,mid,zl,mid));
    49     return ans;
    50 }
    51 int getr(int x,int l,int r,int zl,int zr){
    52     if(zl>zr)return 0;
    53     if(zl<=l&&r<=zr)return rmx[x];
    54     int mid=(l+r)/2,ans=0;
    55     if(mid<zr)ans=getr(rc[x],mid+1,r,zl,zr);
    56     if(zl<=mid)ans=max(ans,getr(lc[x],l,mid,zl,zr)+getsum(rc[x],mid+1,r,mid+1,zr));
    57     return ans;
    58 }
    59 bool check(int x){
    60     int z=getsum(rt[x],1,n,q[1],q[2]);//cout<<z<<endl;
    61     int w=getl(rt[x],1,n,q[2]+1,q[3]);//cout<<w<<endl;
    62     int k=getr(rt[x],1,n,q[0],q[1]-1);//cout<<k<<endl;
    63     if(z+w+k>=0)return 1;
    64     else return 0;
    65 }
    66 inline int find(){
    67     int l=1,r=n,mid;
    68     while(l<r){
    69         mid=(l+r+1)/2;
    70         if(check(mid))l=mid;
    71         else r=mid-1;
    72     }return l;
    73 }
    74 int main(){
    75     scanf("%d",&n);
    76     int x;
    77     for(int i=1;i<=n;i++){ scanf("%d",&x); a[i]=make_pair(x,i); }
    78     sort(a+1,a+1+n);build(rt[1],1,n);
    79     for(int i=2;i<=n;i++){ rt[i]=rt[i-1];inser(rt[i],rt[i],1,n,a[i-1].second); }
    80     int ans=0;scanf("%d",&m);
    81     for(int i=1;i<=m;i++){
    82         scanf("%d%d%d%d",&q[0],&q[1],&q[2],&q[3]);
    83         q[0]=(q[0]+ans)%n+1;q[1]=(q[1]+ans)%n+1;
    84         q[2]=(q[2]+ans)%n+1;q[3]=(q[3]+ans)%n+1;
    85         sort(q,q+4);ans=a[find()].first;
    86         printf("%d
    ",ans);
    87     }
    88     return 0;
    89 }
    View Code

  • 相关阅读:
    postmessage
    input、textarea等输入框输入中文时,拼音在输入框内会触发input事件的问题
    h5判断设备是ios还是android
    js获取地址栏的参数
    BootStrap 响应式布局
    前端框架 BootStrap 快速入门(Hallo Word)
    HTML + CSS + JavaScript 实现注册页面信息验证(表单验证)
    HTML + CSS + JavaScript 实现勾选动态表格中的记录
    JavaScript常见的事件监听
    HTML + CSS + JavaScript 实现简单的动态表格
  • 原文地址:https://www.cnblogs.com/137shoebills/p/8805219.html
Copyright © 2020-2023  润新知