一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整。
给你一个长度为n的序列s。
回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数。
其中a 位置也从0开始标号。
我会使用一些方式强制你在线。
一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整。
给你一个长度为n的序列s。
回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数。
其中a 位置也从0开始标号。
我会使用一些方式强制你在线。
第一行序列长度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]。
输入保证满足条件。
Q行依次给出询问的答案。
0:n,Q<=100
1,...,5:n<=2000
0,...,19:n<=20000,Q<=25000
每次先二分一个中位数,判断是否可行。
我们考虑如何判断该中位数数是否可行?将序列中的数比当前数小的赋值成-1,大的赋值成1,如果一段区间的和为0,那么该数就是区间的中位数。我们现在考虑[a,b],[c,d]的限制,如果[a,b]中右端连续一段的最大值+(b,c)的区间和+[c,d]中左端连续一段的最大值>=0的话,那么就能说明中位数>=当前二分到的数。
如何维护针对每次数的1,-1序列呢?将数从小到大排序,我们可以初始时令序列为全1的序列,当我们对于一个数建树的时候,我们只需要在前一个数序列的基础上将上一个数的位置改成-1即可。然后就行普通的线段数一样,维护区间总和,区间右端连续、左端连续一段的最大值即可。
#include
#include
#include
#include
#include
#define N 4000003
using namespace std;
int a1[N],b[N],sz,n,m,root[N],q[10];
struct data{
int l,r,lx,rx,sum;
}tr[N];
int cmp(int x,int y)
{
return a1[x]rr) return 0;
if (ll<=l&&r<=rr) return tr[now].sum;
int mid=(l+r)/2;
int ans=0;
if (ll<=mid) ans+=query(tr[now].l,l,mid,ll,rr);
if (rr>mid) ans+=query(tr[now].r,mid+1,r,ll,rr);
return ans;
}
int findl(int now,int l,int r,int ll,int rr)
{
if (ll>rr) return 0;
if (ll<=l&&r<=rr) return tr[now].lx;
int mid=(l+r)/2; int ans=-1000000000;
if (ll<=mid) ans=max(ans,findl(tr[now].l,l,mid,ll,rr));
if (rr>mid){
int t=query(now,l,r,ll,mid);
ans=max(ans,t+findl(tr[now].r,mid+1,r,ll,rr));
}
return ans;
}
int findr(int now,int l,int r,int ll,int rr)
{
if (ll>rr) return 0;
if (ll<=l&&r<=rr) return tr[now].rx;
int mid=(l+r)/2; int ans=-1000000000;
if (rr>mid) ans=max(ans,findr(tr[now].r,mid+1,r,ll,rr));
if (ll<=mid){
int t=query(now,l,r,mid+1,rr);
ans=max(ans,t+findr(tr[now].l,l,mid,ll,rr));
}
return ans;
}
bool pd(int now,int a,int b,int c,int d)
{
int val=0;
val+=query(root[now],0,n-1,b+1,c-1); //cout<=0;
}
int solve(int a,int b,int c,int d)
{
int l=0; int r=n-1; int ans=0;
while (l<=r){
int mid=(l+r)/2;
if (pd(mid,a,b,c,d)) ans=mid,l=mid+1;
else r=mid-1;
}
return ans;
}
int main()
{
freopen("a.in","r",stdin);
freopen("my.out","w",stdout);
scanf("%d",&n);
for (int i=0;i