• bzoj 2653 洛谷 P2839 [国家集训队] middle


    2653: middle

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 2381  Solved: 1340
    [Submit][Status][Discuss]

    Description

    一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整。给你一个
    长度为n的序列s。回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数。
    其中a<b<c<d。位置也从0开始标号。我会使用一些方式强制你在线。

     

    Input

    第一行序列长度n。接下来n行按顺序给出a中的数。
    接下来一行Q。然后Q行每行a,b,c,d,我们令上个询问的答案是
    x(如果这是第一个询问则x=0)。
    令数组q={(a+x)%n,(b+x)%n,(c+x)%n,(d+x)%n}。
    将q从小到大排序之后,令真正的
    要询问的a=q[0],b=q[1],c=q[2],d=q[3]。  
    输入保证满足条件。
    第一行所谓“排过序”指的是从小到大排序!
    n<=20000,Q<=25000
     

     

    Output

    Q行依次给出询问的答案。

     

    Sample Input

    5
    170337785
    271451044
    22430280
    969056313
    206452321
    3
    3 1 0 2
    2 3 1 4
    3 1 4 0

    Sample Output

    271451044
    271451044
    969056313
     
    emmm这道题就是一道二分答案主席树 二分我的中位数是什么 然后check判断他是否满足条件
    那么怎么判断呢 对于一段区间 我们假设现在我们要check的中位数是x  对应这个区间我们建立一棵线段树
    若一个数 ≥ x 那么这个数在对应线段树里面的值设为1 否则设为 - 1 
    那么对应这一段的区间和如果等于0 那么这个数就可以作为这段区间的中位数
    如果 > 0 则表示这段区间内比他大的数偏多 也就是说我们现在枚举的这个数相对于中位数偏小 反之偏大
    那么很显然这个东西是满足二分的 
    但是又出现了一个问题 就是我们怎么搞每一个数对应的区间的值吧 肯定不可能是对于每一个数都开一棵线段树
    但是肯定不可能 时间空间都不够用  这时候就想到了主席树 
    然而这个主席树是怎么建立的呢 我们先对应所有的值都排一边序(要存储他们的原位置)
    那么对于i + 1这个位置上的数对应的主席树 他相对于 i 这个位置上的数对应的主席树
    发生的变化是不是就是将原数组中 i 对应的位置上的值从 1 改成 - 1 所以就很容易维护了
    那么怎么对于[a,b] [c,d]查询呢 按照题意 [b,c]是必须选的 求区间和即可那么要使中位数最大 就要使我们所求的区间和尽可能大
    也就是求从b起向左的最大区间和 和从c起向右的最大区间和 求个和 根据上述判断方式二分
    然后就这样 我wa了好几次 竟然是查询右儿子的时候写的是 l 到 mid 丢脸...
     
    代码
    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 20000 + 10;
    int a,b,c,d,T,n,w[N],sum[32 * N],ls[32 * N],rs[32 * N];
    int rmax[32 * N],lmax[32 * N],rt,root[N],q[10],ans = 0;
    
    struct node{
        int val,pos;
    }s[N];
    
    void update(int nd) {
        
        sum[nd] = sum[ls[nd]] + sum[rs[nd]];
        rmax[nd] = max(rmax[rs[nd]],sum[rs[nd]] + rmax[ls[nd]]);
        lmax[nd] = max(lmax[ls[nd]],sum[ls[nd]] + lmax[rs[nd]]);
    }
    
    int build(int l,int r) {
        
        int nd = ++ rt;
        if(l == r) {
            sum[nd] = lmax[nd] = rmax[nd] = 1;
            return nd;
        }
        int mid = (l + r) >> 1;
        ls[nd] = build(l,mid);
        rs[nd] = build(mid + 1,r);
        update(nd);
        return nd;
    }
    
    int modify(int pre,int l,int r,int pos) {
        
        int nd = ++ rt;
        sum[nd] = sum[pre]; ls[nd] = ls[pre],rs[nd] = rs[pre];
        if(l == r) {
            sum[nd] = -1;
            rmax[nd] = 0;
            lmax[nd] = 0;
            return nd;
        }
        int mid = (l + r) >> 1;
        if(pos <= mid) ls[nd] = modify(ls[pre],l,mid,pos);
        else rs[nd] = modify(rs[pre],mid + 1,r,pos);
        update(nd);
        return nd;
    }
    
    bool cmp(const node & a,const node & b) {
        
        return a.val < b.val;
    }
    
    int query(int nd,int l,int r,int L,int R) {
        
        if(l > R || r < L) return 0;
        if(l >= L && r <= R) return sum[nd];
        int mid = (l + r) >> 1,ans = 0;
        if(L <= mid) ans += query(ls[nd],l,mid,L,R);
        if(mid < R)  ans += query(rs[nd],mid + 1,r,L,R);
        return ans;
    }
    
    int query_r(int nd,int l,int r,int L,int R) {
        
        if(l > R || r < L) return 0;
        if(l >= L && r <= R) return rmax[nd];
        int mid = (l + r) >> 1,ans = 0;
        if(mid < R) ans = query_r(rs[nd],mid + 1,r,L,R);
        if(L <= mid) {
            int l_rmax = query_r(ls[nd],l,mid,L,R);
            int r_sum = query(ls[nd],mid + 1,r,L,R);
            ans = max(ans,l_rmax + r_sum);
        }
        return ans;
    }
    
    int query_l(int nd,int l,int r,int L,int R) {
        
        if(L > R) return 0; 
        if(l >= L && r <= R) return lmax[nd];
        int mid = (l + r) >> 1,ans = 0;
        if(L <= mid) ans = query_l(ls[nd],l,mid,L,R);
        if(mid < R) {
            int r_lmax = query_l(ls[nd],mid + 1,r,L,R);
            int l_sum = query(ls[nd],l,mid,L,R);
            ans = max(ans,r_lmax + l_sum);
        }
        return ans;
    }
    
    bool check(int mid) {
        
        int ab = query_r(root[mid],1,n,q[1],q[2] - 1);
        int bc = query(root[mid],1,n,q[2],q[3]);
        int cd = query_l(root[mid],1,n,q[3] + 1,q[4]);
        if(ab + bc + cd >= 0) return true;
        return false;
    }
    
    int find( ) {
        
        int l = 1,r = n,ans = 0;
        while(l <= r) {
            int mid = (l + r) >> 1;
            if(check(mid)) ans = mid,l = mid + 1;
            else r = mid - 1;
        }
        return ans;
    }
    
    int main( ) {
        
        scanf("%d",& n);
        for(int i = 1;i <= n;i ++) {
            scanf("%d",& w[i]);
            s[i].pos = i; s[i].val = w[i];
        }
        sort(s + 1,s + n + 1,cmp);
        scanf("%d",& T);
        root[1] = build(1,n);
        for(int i = 2;i <= n;i ++) {
            root[i] = modify(root[i - 1],1,n,s[i - 1].pos);
        }
        while(T --) {
            scanf("%d%d%d%d",& a,& b,& c,& d);
            q[1] = (a + ans) % n + 1; q[2] = (b + ans) % n + 1;
            q[3] = (c + ans) % n + 1; q[4] = (d + ans) % n + 1;
            sort(q + 1,q + 5);
            ans = s[find( )].val;
            printf("%d
    ",ans);
        }
    }
  • 相关阅读:
    SQLSERVER查询所有数据库名,表名,和字段名
    SQL通过拆分某字段中的内容来实现与对应表连接查询
    [SPOJ]CIRU 圆并
    有关反演和GCD
    docker部署 jenkins
    mongoDB学习记录(二)
    docker动态修改容器限制
    ORACLE数据库误操作DELETE并且提交数据库之后如何恢复被删除的数据
    用8个命令调试Kubernetes集群
    db2服务器linux的cache过高原因
  • 原文地址:https://www.cnblogs.com/Rubenisveryhandsome/p/9508058.html
Copyright © 2020-2023  润新知