BZOJ 2653 middle (可持久化线段树+中位数+线段树维护最大子序和)

题意:

左端点在[a,b],右端点在[c,d],求这个线段里中位数(上取整)最大值

思路:

对数组离散化,对每一个值建中位数的可持久化线段树(有重复也没事),就是对于root[i],大于等于i的值为1,小于的为-1,

从小到大插入可持久化线段树即可

如果中位数为m,那么从左端点到右端点[l,r]的序列和应该>=0,我们只需要二分这个m检查是不是序列和>=0即可

满足左端点在[a,b],右端点在[c,d]的子序列和的最大值,就是我们在用线段树维护最大子序和时的

[b+1,c-1]的sum+[a,b]的maxr+[c,d]的maxl

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<deque>
#include<set>
#include<vector>
#include<map>
#include<functional>
    
#define fst first
#define sc second
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
//#define lc root<<1
//#define rc root<<1|1
#define lowbit(x) ((x)&(-x)) 

using namespace std;

typedef double db;
typedef long double ldb;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PI;
typedef pair<ll,ll> PLL;

const db eps = 1e-6;
const int mod = 1e9+7;
const int maxn = 2e5+100;
const int maxm = 2e6+100;
const int inf = 0x3f3f3f3f;
const db pi = acos(-1.0);

int n;
PI a[maxn];
int q;
vector<ll>v;
int getid(ll x){
    return lower_bound(v.begin(), v.end(), x)-v.begin()+1;
}
bool cmp(PI a, PI b){
    if(a.fst==b.fst)return a.sc<b.sc;
    return a.fst<b.fst;
}
int root[maxn];
struct Node{
    int maxl,maxr;
    int sum;
}node[maxn*60];
int ls[maxn],rs[maxn];
int tot,totn;
void build(int l, int r, int &root){
    root = ++tot;
    int mid = (l+r)>>1;
    if(l==r){
        node[root].maxl=node[root].maxr=node[root].sum=1;
        return;
    }
    build(l, mid, ls[root]);
    build(mid+1, r, rs[root]);
    node[root].maxl=max(node[ls[root]].sum+node[rs[root]].maxl, node[ls[root]].maxl);
    node[root].maxr=max(node[rs[root]].sum+node[ls[root]].maxr, node[rs[root]].maxr);
    node[root].sum=node[ls[root]].sum+node[rs[root]].sum;
    return;
}
void insert(int lst, int &now, int l, int r, int p){
    now = ++tot;
    ls[now]=ls[lst];
    rs[now]=rs[lst];
    node[now] = node[lst];
    int mid = (l+r)>>1;
    if(l==r){
        node[now].maxl=node[now].maxr=node[now].sum=-1;
        return;
    }
    if(p<=mid)insert(ls[lst], ls[now], l, mid, p);
    else insert(rs[lst], rs[now], mid+1, r, p);
    node[now].maxl=max(node[ls[now]].sum+node[rs[now]].maxl, node[ls[now]].maxl);
    node[now].maxr=max(node[rs[now]].sum+node[ls[now]].maxr, node[rs[now]].maxr);
    node[now].sum=node[ls[now]].sum+node[rs[now]].sum;
}
Node query(int ql, int qr, int l, int r, int now){
    
    int mid = (l+r)>>1;
    if(l==ql&&r==qr){
        return node[now];
    }
    else if(mid>=qr){
        return query(ql, qr, l, mid, ls[now]);
    }
    else if(mid<ql){
        return query(ql, qr, mid+1, r, rs[now]);
    }
    else{
        Node ans;
        Node lc=query(ql,mid,l,r,now);
        Node rc=query(mid+1,qr,l,r,now);
        ans.sum=lc.sum+rc.sum;
        ans.maxl=max(lc.sum+rc.maxl,lc.maxl);
        ans.maxr=max(rc.sum+lc.maxr,rc.maxr);
        return ans;
    }
}
void dfs(int x){
    printf("%d %d %d %d %d %d\n",x,ls[x],rs[x],node[x].sum,node[x].maxl,node[x].maxr);
    if(ls[x])dfs(ls[x]);
    if(rs[x])dfs(rs[x]);
}
int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; i++){
        scanf("%d" ,&a[i].fst);
        a[i].sc=i;
        v.pb(a[i].fst);
    }
    sort(v.begin(), v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
    totn=v.size();
    int lstans = 0;
    int tmp[5];
    sort(a+1,a+1+n,cmp);
    build(1,n,root[0]);
    for(int i = 1; i <= n; i++){
        insert(root[i-1],root[i],1,n,a[i].sc);
    }int q;
    //dfs(root[4]);
    scanf("%d", &q);
    while(q--){
        for(int i = 1; i <= 4; i++){
            scanf("%d", &tmp[i]);
            tmp[i]=(tmp[i]+lstans)%n;
        }
        sort(tmp+1,tmp+1+4);
        int l = 0;
        int r = n+1;
        int ans = 0;
        
        while(l<=r){
            int mid = (l+r)>>1;
            int res=max(query(tmp[1]+1,tmp[2]+1-1,1,n,root[mid-1]).maxr,0);
            res+=query(tmp[2]+1,tmp[3]+1,1,n,root[mid-1]).sum;
            res+=max(query(tmp[3]+1+1,tmp[4]+1,1,n,root[mid-1]).maxl,0);
            if(res>=0){
                ans=mid;
                l=mid+1;
            }
            else r = mid-1;
        }
        printf("%d\n",lstans=v[ans-1]);
    }
    return 0;
}
/*
5
2 4 1 5 3
3
3 1 0 2
2 3 1 4
3 1 4 0

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

 

posted @ 2019-06-10 14:12  wrjlinkkkkkk  阅读(266)  评论(0编辑  收藏  举报