主席树(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\n", la=a[b[l]]); } return 0; }
posted @ 2016-12-21 19:43  Monster_Yi  阅读(185)  评论(0编辑  收藏  举报