1. 程式人生 > >bzoj 2653: middle

bzoj 2653: middle

大連 sin typedef unique 我們 長度 pri scrip right

Description

一個長度為n的序列a,設其排過序之後為b,其中位數定義為b[n/2],其中a,b從0開始標號,除法取下整。給你一個 長度為n的序列s。回答Q個這樣的詢問:s的左端點在[a,b]之間,右端點在[c,d]之間的子序列中,最大的中位數。 其中a<b<c<d。位置也從0開始標號。我會使用一些方式強制你在線。

Input

第一行序列長度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]。   輸入保證滿足條件。 第一行所謂“排過序”指的是從大到小排序!

Output

Q行依次給出詢問的答案。

Sample Input

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

271451044
271451044
969056313

Sample Output

HINT

0:n,Q<=100

1,...,5:n<=2000

0,...,19:n<=20000,Q<=25000

Source

陳老師的題,然而大佬們都是隨意切。。。

首先記住中位數的套路,二分答案然後>=mid的為1,<mid的為-1;

那麽check的話我們相當於是要找一個左端點在[a,b],右端點在[c,d]且子段和>=0的子段。。。

我一開始想了一個傻逼東西,每個點維護sum[i]表示1-i的前綴和,然後查詢[c,d]中的sum_max,查詢[a,b]中的sum_min;

然後前綴和相減算最大子段和,即sum_max-sum_min。。。

但這個東西顯然只能處理一次詢問,因為每次二分後都需要O(n)的時間來重構sum[i],顯然做不了很多次詢問。。。

考慮換一種做法,把詢問拆為三個:

[a,b]的後綴最大連續值,[b+1,c-1]的子段和,[c,d]的前綴最大連續值,三個相加。。。

這些東西都可以在線段樹上維護。。。現在看來這樣做每次的復雜度跟上面一種做法沒區別。。。

但是他可以加可持久化的特技。。。

考慮把Mid改為Mid+1後,只需要把Mid的權值該為-1,而其他點的權值不需要改動(每次只有單點修改,而維護sum的話就GG)

所以可以用可持久化的那一套理論,對於每一個Mid值都搞一棵線段樹。。

這樣詢問時就可以直接查詢二分值版本的線段樹,而不需要對於每個二分值重構線段樹了。。

具體做法,把Mid從小到大建線段樹,我們以Mid的線段樹為歷史版本,然後Mid+1的線段樹就用可持久化的理論,修改Mid線段樹的一條鏈。。

線段樹上的節點維護三個東西(和,前綴最大值,後綴最大值)就好了。。。

// MADE BY QT666
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
typedef long long ll;
const int N=500050;
vector<int> p[N];
int hsh[N],tot,sz,rt[N],ls[N*20],rs[N*20],sum[N*20],lmax[N*20],rmax[N*20],a[N];
int n,Q,q[10];
void pushup(int x){ 
  sum[x]=sum[ls[x]]+sum[rs[x]];
  lmax[x]=max(lmax[ls[x]],sum[ls[x]]+lmax[rs[x]]);
  rmax[x]=max(rmax[rs[x]],sum[rs[x]]+rmax[ls[x]]);
}
void insert(int x,int &y,int l,int r,int u,int v){
  y=++sz;ls[y]=ls[x],rs[y]=rs[x];
  if(l==r){
    sum[y]=lmax[y]=rmax[y]=v;return;
  }
  int mid=(l+r)>>1;
  if(u<=mid) insert(ls[x],ls[y],l,mid,u,v);
  else insert(rs[x],rs[y],mid+1,r,u,v);
  pushup(y);
}
int query_sum(int x,int l,int r,int xl,int xr){
  if(xl>xr) return 0;
  if(xl<=l&&r<=xr) return sum[x];
  int mid=(l+r)>>1;
  if(xr<=mid) return query_sum(ls[x],l,mid,xl,xr);
  else if(xl>mid) return query_sum(rs[x],mid+1,r,xl,xr);
  else return query_sum(ls[x],l,mid,xl,mid)+query_sum(rs[x],mid+1,r,mid+1,xr);
}
int query_left(int x,int l,int r,int xl,int xr){
  if(xl<=l&&r<=xr) return lmax[x];
  int mid=(l+r)>>1;
  if(xr<=mid) return query_left(ls[x],l,mid,xl,xr);
  else if(xl>mid) return query_left(rs[x],mid+1,r,xl,xr);
  else return max(query_left(ls[x],l,mid,xl,mid),query_sum(ls[x],l,mid,xl,mid)+query_left(rs[x],mid+1,r,mid+1,xr));
}
int query_right(int x,int l,int r,int xl,int xr){
  if(xl<=l&&r<=xr) return rmax[x];
  int mid=(l+r)>>1;
  if(xr<=mid) return query_right(ls[x],l,mid,xl,xr);
  else if(xl>mid) return query_right(rs[x],mid+1,r,xl,xr);
  else return max(query_right(ls[x],l,mid,xl,mid)+query_sum(rs[x],mid+1,r,mid+1,xr),query_right(rs[x],mid+1,r,mid+1,xr));
}
bool check(int mid,int a,int b,int c,int d){
  int part1=query_right(rt[mid],1,n,a,b);
  int part2=query_sum(rt[mid],1,n,b+1,c-1);
  int part3=query_left(rt[mid],1,n,c,d);
  return part1+part2+part3>=0;
}
int main(){
  scanf("%d",&n);
  for(int i=1;i<=n;i++) scanf("%d",&a[i]),hsh[++tot]=a[i];
  sort(hsh+1,hsh+1+tot);tot=unique(hsh+1,hsh+1+tot)-hsh-1;
  for(int i=1;i<=n;i++){
    a[i]=lower_bound(hsh+1,hsh+1+tot,a[i])-hsh,p[a[i]].push_back(i);
  }
  for(int i=1;i<=n;i++){
    if(a[i]>=1) insert(rt[1],rt[1],1,n,i,1);
    else insert(rt[1],rt[1],1,n,i,0);
  }
  for(int i=2;i<=tot;i++){
    rt[i]=rt[i-1];
    for(int j=0;j<p[i-1].size();j++){
      insert(rt[i],rt[i],1,n,p[i-1][j],-1);
    }
  }
  int ans=0;scanf("%d",&Q);
  for(int i=1;i<=Q;i++){
    int a,b,c,d;scanf("%d%d%d%d",&a,&b,&c,&d);
    q[1]=(a+ans)%n,q[2]=(b+ans)%n,q[3]=(c+ans)%n,q[4]=(d+ans)%n;
    sort(q+1,q+1+4);a=q[1]+1,b=q[2]+1,c=q[3]+1,d=q[4]+1;
    int l=1,r=tot;
    while(l<=r){
      int mid=(l+r)>>1;
      if(check(mid,a,b,c,d)) l=mid+1,ans=hsh[mid];
      else r=mid-1;
    }
    printf("%d\n",ans);
  }
  return 0;
}

bzoj 2653: middle