zoukankan      html  css  js  c++  java
  • [bzoj2653]middle

    来自FallDream的博客,未经允许,请勿转载,谢谢


    ditoly太强了 随便切  我被d飞了

    -------------------------------

    由n个数ai,每次询问,给定四个数a,b,c,d,求一个左端点在[a,b],右端点在[c,d]的子序列(原题这么写,但是实际上是子串),使得它的中位数最大。强制在线

    n<=20000 q<=25000

    题解:考虑二分一个答案,然后check一下是否能够取到。

    怎么check呢?假设要check一个数X,那么我们把大等于X的数字看成1,小于的看成-1,如果存在一个子序列的和大等于0,那么这个数字就是合法的。

    所以我们可以维护一棵线段树,直接把每一位看成1或者-1,维护前缀和数组的最大最小值,然后数字从小到大把线段树可持久化一下,每次一个数字从1变成-1就是把一段区间-2,这个我们通过标记永久化实现。

    复杂度$qlog^{2}n$

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define MN 20000
    #define pa pair<int,int>
    #define mp(x,y) make_pair(x,y)
    #define INF 2000000000
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    int n,m,last=0,num[10],a[MN+5],cnt=0,l[MN+5],rt[MN+5];
    pa p[MN+5];
    
    struct data{
        int mx,mn;
        data(int x=0):mx(x),mn(x){}
        data(int x,int y):mx(x),mn(y){}
        data operator*(const data&b){return data(max(mx,b.mx),min(mn,b.mn));} 
        data operator+(int y){return data(mx+y,mn+y);}
    };
    struct node{int l,r,val;data x;}T[MN*60+5];
    
    inline int mark(int x,int k)
    {
        int nx=++cnt;T[nx].l=T[x].l;T[nx].r=T[x].r;
        T[nx].x=T[x].x+k;T[nx].val=T[x].val+k;    
        return nx;
    }
    
    void pushdown(int x)
    {
        T[x].l=mark(T[x].l,T[x].val);
        T[x].r=mark(T[x].r,T[x].val);
        T[x].val=0;
    }
    
    int ins(int x,int l,int r,int ad,int lt=0,int rt=n)
    {
        if(l==lt&&rt==r){return mark(x,ad);}
        int nx=mark(x,0);pushdown(nx);
        int mid=lt+rt>>1;
        if(r<=mid) 
            T[nx].l=ins(T[nx].l,l,r,ad,lt,mid);
        else if(l>mid)
            T[nx].r=ins(T[nx].r,l,r,ad,mid+1,rt);
        else 
            T[nx].l=ins(T[nx].l,l,mid,ad,lt,mid),T[nx].r=ins(T[nx].r,mid+1,r,ad,mid+1,rt);
        T[nx].x=T[T[nx].l].x*T[T[nx].r].x;
        return nx;
    }
    
    int build(int l,int r)
    {
        int x=++cnt,mid=l+r>>1;
        if(l==r) {T[x].x=data(l);return x;}
        T[x].l=build(l,mid);T[x].r=build(mid+1,r);
        T[x].x=T[T[x].l].x*T[T[x].r].x;
        return x;
    }
    
    data query(int x,int l,int r,int lt=0,int rt=n)
    {
        if(l==lt&&rt==r) return T[x].x;
        int mid=lt+rt>>1;
        if(r<=mid) return query(T[x].l,l,r,lt,mid)+T[x].val;
        else if(l>mid) return query(T[x].r,l,r,mid+1,rt)+T[x].val;
        else return query(T[x].l,l,mid,lt,mid)*query(T[x].r,mid+1,r,mid+1,rt)+T[x].val;
    }
    
    int main()
    {    
        n=read();
        for(int i=1;i<=n;i++) a[i]=read();
        for(int i=1;i<=n;i++) p[i]=mp(a[i],i);
        sort(p+1,p+n+1);rt[1]=build(0,n);
        for(int i=2;i<=n;i++)
            rt[i]=ins(rt[i-1],p[i-1].second,n,-2);
        m=read();
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=4;j++) num[j]=(read()+last)%n+1;
            sort(num+1,num+5);
            int a=num[1],b=num[2],c=num[3],d=num[4];
            int L=1,R=n,mid,ans=0;
            while(L<=R)
            {
                mid=L+R>>1;    
                if(query(rt[mid],c,d).mx-query(rt[mid],a-1,b-1).mn>=0) ans=mid,L=mid+1;
                else R=mid-1;
            }
            printf("%d
    ",last=p[ans].first);
        }
        return 0;
    }
  • 相关阅读:
    BadUSB 利用
    java 将函数作为参数传递
    odoo12 修行提升篇之 常用的高阶函数 (二)
    odoo12 修行提升篇之 异步定时任务 (一)
    odoo12 修行基础篇之 利用kanban做分析 点击跳转分析模型列表 (九)
    odoo12 修行基础篇之 kanban (八)
    odoo12 修行基础篇之 记录批处理 (七)
    odoo12 修行基础篇之 列表的筛选和分组 (六)
    odoo12 修行基础篇之 添加记录编码 (五)
    odoo12 修行基础篇之 添加工作流和操作记录 (四)
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj2653.html
Copyright © 2011-2022 走看看