autoint

题意

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

\(n \leq 20000,Q \leq 25000\)

分析

对多个区间取中位数的最大值,但是这些区间都包含一个相同的区间[b+1,c-1]。
可以将[b+1,c-1]区间先排序,再考虑往左右两边扩展。

对于左右两边扩展的数x,扩展后能否更优其实是由x与[b+1,c-1]中位数M的大小决定的。
考虑数列长度对中位数的影响。

  • 奇数:中间的数
  • 偶数:中间靠后的数

那么相当于x=M时也会可能对中位数的变大造成贡献。
因此将大于等于M的x看作1,小于M的x看作-1
如果能在两端找一段和>0,那么M就可能可以变大。
但是两端是分开的,如果要连起来需要考虑中间的部分。
如果中间的一部分也按类似考虑,那么就是检验M是否可行了。

然后须要用到中间[b+1,b-1]部分的和,[a,b]的最大后缀和,[c,d]的最大前缀和,用线段树可以很好解决。
可能出现的M最多只有N种,离散化。然后就可以对于每个M都预处理一遍这个正负1线段树。
但是不可能开N颗线段树。
发现M时候的情况从M-1转移,所需要改变的只有M-1的值。
于是用可持久化线段树就可以解决了。

时间复杂度\(O(N \log N+Q \log^2 N)\)

代码

#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<ctime>
#include<iostream>
#include<string>
#include<vector>
#include<list>
#include<deque>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<complex>
#pragma GCC optimize ("O0")
using namespace std;
template<class T> inline T read(T&x)
{
    T data=0;
    int w=1;
    char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            w=-1;
        ch=getchar();
    }
    while(isdigit(ch))
        data=10*data+ch-'0',ch=getchar();
    return x=data*w;
}
typedef long long ll;
const int INF=0x7fffffff;

const int MAXN=2e4+7,MAXT=MAXN*20; // 16+4
int n;

struct node
{
    int v,p;
    bool operator<(const node&rhs)const
    {
        return v<rhs.v;
    }
}a[MAXN]; // basz 0 to simplify querying

int sz,root[MAXN];
struct PreSegTree
{
    int L[MAXT],R[MAXT];
    int sum[MAXT],pre[MAXT],suf[MAXT];
    
    void pushup(int now)
    {
        sum[now]=sum[L[now]]+sum[R[now]];
        pre[now]=max(pre[L[now]],sum[L[now]]+pre[R[now]]);
        suf[now]=max(suf[R[now]],sum[R[now]]+suf[L[now]]);
    }
    
    void build(int&now,int l,int r)
    {
        now=++sz;
        if(l==r)
        {
            sum[now]=pre[now]=suf[now]=1;
            return;
        }
        int mid=(l+r)>>1;
        build(L[now],l,mid);
        build(R[now],mid+1,r);
        pushup(now);
    }
    
    int qsum(int now,int l,int r,int ql,int qr)
    {
        if(ql<=l&&r<=qr)
        {
            return sum[now];
        }
        int mid=(l+r)>>1,ans=0;
        if(ql<=mid)
            ans+=qsum(L[now],l,mid,ql,qr);
        if(qr>=mid+1)
            ans+=qsum(R[now],mid+1,r,ql,qr);
        return ans;
    }
    
    int qpre(int now,int l,int r,int ql,int qr)
    {
        if(ql<=l&&r<=qr)
        {
            return pre[now];
        }
        int mid=(l+r)>>1;
        if(qr<=mid)
            return qpre(L[now],l,mid,ql,qr);
        if(ql>=mid+1)
            return qpre(R[now],mid+1,r,ql,qr);
        return max(qpre(L[now],l,mid,ql,qr),qsum(L[now],l,mid,ql,qr)+qpre(R[now],mid+1,r,ql,qr));
    }
    
    int qsuf(int now,int l,int r,int ql,int qr)
    {
        if(ql<=l&&r<=qr)
        {
            return suf[now];
        }
        int mid=(l+r)>>1;
        if(qr<=mid)
            return qsuf(L[now],l,mid,ql,qr);
        if(ql>=mid+1)
            return qsuf(R[now],mid+1,r,ql,qr);
        return max(qsuf(R[now],mid+1,r,ql,qr),qsum(R[now],mid+1,r,ql,qr)+qsuf(L[now],l,mid,ql,qr));
    }
    
    void change(int&now,int l,int r,int p,int v)
    {
        ++sz;
        L[sz]=L[now],R[sz]=R[now];
        now=sz;
        if(l==r)
        {
            sum[now]=pre[now]=suf[now]=v;
            return;
        }
        int mid=(l+r)>>1;
        if(p<=mid)
            change(L[now],l,mid,p,v);
        else
            change(R[now],mid+1,r,p,v);
        pushup(now);
    }
}T;

int q[4];

bool judge(int rt,int a,int b,int c,int d)
{
    int res=0;
    if(b+1<=c-1)
        res+=T.qsum(rt,0,n-1,b+1,c-1);
    res+=T.qsuf(rt,0,n-1,a,b);
    res+=T.qpre(rt,0,n-1,c,d);
    return res>=0;
}

int main()
{
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);
    read(n);
    for(int i=0;i<n;++i)
    {
        read(a[i].v);
        a[i].p=i;
    }
    sort(a,a+n); // 特殊离散化,后面二分答案的排名 
    T.build(root[0],0,n-1);
    for(int i=1;i<n;++i)
    {
        root[i]=root[i-1];
        T.change(root[i],0,n-1,a[i-1].p,-1); // change the one 1 smaller than it
    }
    int Q,ans=0;
    read(Q);
    while(Q--)
    {
        read(q[0]);read(q[1]);
        read(q[2]);read(q[3]);
        (q[0]+=ans)%=n,(q[1]+=ans)%=n,
        (q[2]+=ans)%=n,(q[3]+=ans)%=n;
        sort(q,q+4);
        int l=0,r=n-1,x;
        while(l<=r)
        {
            int mid=(l+r)>>1;
            if(judge(root[mid],q[0],q[1],q[2],q[3]))
                x=mid,l=mid+1;
            else
                r=mid-1;
        }
        ans=a[x].v;
        printf("%d\n",ans);
    }
//  fclose(stdin);
//  fclose(stdout);
    return 0;
}

相关文章:

  • 2021-07-10
  • 2021-06-14
  • 2022-01-19
  • 2021-06-09
猜你喜欢
  • 2021-10-22
  • 2021-07-24
  • 2021-11-18
  • 2022-01-17
  • 2021-10-19
相关资源
相似解决方案