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;
    }
  • 相关阅读:
    飞入飞出效果
    【JSOI 2008】星球大战 Starwar
    POJ 1094 Sorting It All Out
    POJ 2728 Desert King
    【ZJOI 2008】树的统计 Count
    【SCOI 2009】生日快乐
    POJ 3580 SuperMemo
    POJ 1639 Picnic Planning
    POJ 2976 Dropping Tests
    SPOJ QTREE
  • 原文地址:https://www.cnblogs.com/BLADEVIL/p/3673118.html
Copyright © 2011-2022 走看看