zoukankan      html  css  js  c++  java
  • bzoj 2653 二分答案+可持久化线段树

      首先离散化,然后我们知道如果对于一个询问的区间[l1,r1],[l2,r2],我们二分到一个答案x,将[l1,r2]区间中的元素大于等于x的设为1,其余的设为-1,那么如果[l1,r1]的最大右区间和加上[r1,l2]的区间和加上[l2,r2]的最大左区间和大于等于0,那么最大的中位数一定大于等于x。因为这个区间中大于等于x的数量超过了一半,那么我们可以二分答案,然后判断最大的合法(见上文)区间和是否大于等于0。

      那么对于每个我们二分的值的区间-1,1情况我们不能建立n颗线段树,我们可以建立可持久化线段树来维护这个,最开始的初始值都为1,设rot[x]为二分的值为x的时候区间的1,-1情况的线段树,可以由rot[x-1]这颗线段树继承过来。

      反思:之前写的可持久化线段树都是建立的权值线段树,这次是用线段树维护区间值的,而且之前对于rot[x]只会有一次插入,这道题的rot[x]可能会有多次插入,在这里纠结了半天。还有我就是最后输出的是adr[ans],但是前面强制在线的时候我加的是ans,忘了改了= =。

    /**************************************************************
        Problem: 2653
        User: BLADEVIL
        Language: C++
        Result: Accepted
        Time:2012 ms
        Memory:18196 kb
    ****************************************************************/
     
    //By BLADEVIL
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define maxn 50010
     
    using namespace std;
     
    struct rec {
        int key,ans,num;
        rec() {
            key=ans=num=0;
        }
    }a[maxn];
     
    struct segment {
        int left,right,maxr,maxl,sum;
        int son[2];
        segment() {
            left=right=maxr=maxl=sum=0;
            memset(son,0,sizeof son);
        }
    }t[12*maxn];
     
    int n,m,tot;
    int rot[maxn],adr[maxn];
     
    bool cmp1(rec x,rec y) {
        return x.ans<y.ans;
    }
     
    bool cmp2(rec x,rec y) {
        return x.num<y.num;
    }
     
    void update(int x) {
        t[x].sum=t[t[x].son[0]].sum+t[t[x].son[1]].sum;
        t[x].maxl=max(t[t[x].son[0]].sum+t[t[x].son[1]].maxl,t[t[x].son[0]].maxl);
        t[x].maxr=max(t[t[x].son[1]].sum+t[t[x].son[0]].maxr,t[t[x].son[1]].maxr);
    }
     
    void build(int &x,int l,int r) {
        if (!x) x=++tot;
        t[x].left=l; t[x].right=r;
        if (l==r) {
            t[x].sum=t[x].maxl=t[x].maxr=1;
            return ;
        }
        int mid=t[x].left+t[x].right>>1;
        build(t[x].son[0],l,mid); build(t[x].son[1],mid+1,r);
        update(x);
    }
     
    void insert(int &x,int rot,int y) {
        if (!x) x=++tot;
        t[x].left=t[rot].left; t[x].right=t[rot].right;
        if (t[x].left==t[x].right) {
            t[x].sum=t[x].maxl=t[x].maxr=-1;
            return ;
        }
        int mid=t[x].left+t[x].right>>1;
        if (y>mid) {
            if (!t[x].son[0]) t[x].son[0]=t[rot].son[0];
            if (t[x].son[1]==t[rot].son[1]) t[x].son[1]=0;
            insert(t[x].son[1],t[rot].son[1],y);
        } else {
            if (!t[x].son[1]) t[x].son[1]=t[rot].son[1];
            if (t[x].son[0]==t[rot].son[0]) t[x].son[0]=0;
            insert(t[x].son[0],t[rot].son[0],y);
        }
        update(x);
    }
     
    segment combine(segment x,segment y) {
        segment ans;
        ans.sum=x.sum+y.sum;
        ans.maxl=max(x.sum+y.maxl,x.maxl);
        ans.maxr=max(y.sum+x.maxr,y.maxr);
        return ans;
    }
     
    segment query(int x,int l,int r) {
        if ((t[x].left==l)&&(t[x].right==r)) return t[x];
        int mid=t[x].left+t[x].right>>1;
        if (l>mid) return query(t[x].son[1],l,r); else
        if (r<=mid) return query(t[x].son[0],l,r); else
            return combine(query(t[x].son[0],l,mid),query(t[x].son[1],mid+1,r));
    }
     
    int main(){
        scanf("%d",&n);
        for (int i=1;i<=n;i++) scanf("%d",&a[a[i].num=i].ans);
        sort(a+1,a+1+n,cmp1);
        int sum=1,cur=a[1].ans; adr[1]=a[1].ans;
        for (int i=1;i<=n;i++) if (a[i].ans==cur) a[i].key=sum; else a[i].key=++sum,adr[sum]=cur=a[i].ans;
        //sort(a+1,a+1+n,cmp2);
        //for (int i=1;i<=n;i++) printf("%d ",a[i].key); printf("
    ");
        build(rot[0],1,n);
        for (int i=1;i<=n;i++) insert(rot[a[i].key],rot[a[i].key-1],a[i].num);
        //for (int i=1;i<=tot;i++) printf("%d %d %d %d %d %d %d
    ",i,t[i].left,t[i].right,t[i].son[0],t[i].son[1],t[i].maxl,t[i].maxr);
        //for (int i=1;i<=n;i++) printf("%d ",adr[i]); printf("
    ");
        scanf("%d",&m);
        int ans=0;
        while (m--) {
            int ask[5]; for (int i=1;i<=4;i++) scanf("%d",&ask[i]);
            for (int i=1;i<=4;i++) ask[i]=(ask[i]+adr[ans])%n+1;
            ans=0;
            sort(ask+1,ask+5);
            int l=1,r=n;
            while (l<=r) {
                int mid=l+r>>1,TOT=0;
                //printf("%d %d %d
    ",l,r,a[mid].key);
                //printf("%d %d
    ",l,r);
                segment a1=query(rot[a[mid].key-1],ask[1],ask[2]),a2=query(rot[a[mid].key-1],ask[3],ask[4]);
                if (ask[2]+1<=ask[3]-1) TOT=query(rot[a[mid].key-1],ask[2]+1,ask[3]-1).sum; 
                //printf("%d
    ",TOT);
                TOT+=a1.maxr+a2.maxl; //printf("%d
    ",TOT);
                //printf("%d
    ",a1.maxr);
                if (TOT>=0) ans=a[mid].key,l=mid+1; else r=mid-1;
            }
            printf("%d
    ",adr[ans]);
        }
        return 0;
    }
  • 相关阅读:
    struts1 Hibernate3初学
    java学习笔记
    改良程序需要的11个技巧
    SharePoint 2010 PowerShell 系列 之 应用总结
    PowerPivot for excel 100 Create KPI
    Sharepoint 2010 控件系统 之 扩展 SaveButton
    Entity Framework 5 一个模型多个关系图 期待已久了
    PowerPivot for Sharepoint 2010 配制及常见错误
    SharePoint 2010 PowerShell 系列 之 应用总结 (二)
    Sharepoint 2010 控件系统 之 TextField、LookupField、NoteField、RichTextField、SaveButton
  • 原文地址:https://www.cnblogs.com/BLADEVIL/p/3673118.html
Copyright © 2011-2022 走看看