• 主席树(BZOJ2653)


    考虑二分答案,设为k,将大于等于k的元素设为1,小于的设为-1,如果某一段的和>=0,说明这段的中位数>=k.

    对于每组询问,二分完后查询新序列的最大子段和即可。

    但是不能开n棵线段树,观察到如果将原序列从小到大排序后,每加一个元素只会修改一个位置的值,所以用个主席树维护最大子段和即可。

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    #define lx t[x].l
    #define rx t[x].r
    #define m ((l+r)>>1)
    #define lc lx,l,m
    #define rc rx,m+1,r
    
    const int N = 20005;
    int n,q,tt,la,l1,r1,l2,r2,c[4],a[N],b[N],rt[N];
    struct nd {int l,r,s,ls,rs;}t[300000];
    bool cmp(int x, int y) {return a[x] < a[y];}
    
    void bd(int &x, int l, int r) {
        x = ++tt, t[x].s = t[x].ls = t[x].rs = r-l+1;
        if(l == r) return;
        bd(lc), bd(rc);
    }
    
    void upd(int lt, int x, int l, int r, int v) {
        if(l == r) {t[x].s = t[x].ls = t[x].rs = -1; return;}
        if(v <= m) rx = t[lt].r, t[x].l = ++tt, upd(t[lt].l, lc, v);
        else lx = t[lt].l, t[x].r = ++tt, upd(t[lt].r, rc, v);
        t[x].s=t[lx].s+t[rx].s;
    t[x].ls=max(t[lx].ls,t[lx].s+t[rx].ls),t[x].rs=max(t[rx].rs,t[rx].s+t[lx].rs); } int qry2(int x, int l, int r, int L, int R) { if(l >= L && r <= R) return t[x].s; if(L > m) return qry2(rc, L, R); if(R <= m) return qry2(lc, L, R); return qry2(lc, L, R)+qry2(rc, L, R); } int qry1(int x, int l, int r, int L, int R) { if(l >= L && r <= R) return t[x].rs; if(L > m) return qry1(rc, L, R); if(R <= m) return qry1(lc, L, R); return max(qry1(rc,L,R),qry1(lc,L,R)+qry2(rc,L,R)); } int qry3(int x, int l, int r, int L, int R) { if(l >= L && r <= R) return t[x].ls; if(L > m) return qry3(rc, L, R); if(R <= m) return qry3(lc, L, R); return max(qry3(lc,L,R),qry3(rc,L,R)+qry2(lc,L,R)); } int main() { scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d", &a[i]), b[i] = i; sort(b+1, b+1+n, cmp), bd(rt[0], 1, n); for(int i = 1; i <= n; i++) rt[i] = ++tt, upd(rt[i-1], rt[i], 1, n, b[i]); scanf("%d", &q); while(q--) { scanf("%d%d%d%d", &l1, &r1, &l2, &r2); c[0] = (l1+la)%n+1, c[1] = (r1+la)%n+1, c[2] = (l2+la)%n+1, c[3] = (r2+la)%n+1; sort(c, c+4), l1 = c[0], r1 = c[1], l2 = c[2], r2 = c[3]; int l = 1, r = n; while(l < r) { int t1 = qry1(rt[m],1,n,l1,r1)+qry3(rt[m],1,n,l2,r2),t2; if(r1+1 < l2) t2 = qry2(rt[m],1,n,r1+1,l2-1); else t2 = 0; if(t1+t2 >= 0) l = m+1; else r = m; } printf("%d ", la=a[b[l]]); } return 0; }
  • 相关阅读:
    html5和css3的新特性
    实现全选按钮的js代码
    window.location对象获取浏览器地址栏的地址信息
    珍爱网前端笔试题之九宫格的实现
    c# array arraylist list
    解决visual studio不能发现单元测试、无法运行单元测试的方法
    Linux 学习笔记
    C++语言学习
    C语言学习
    日志打印,设置开关类【编程技巧】
  • 原文地址:https://www.cnblogs.com/juruolty/p/6208870.html
Copyright © 2020-2023  润新知