[國家集訓隊]middle——中位數思維題
阿新 • • 發佈:2021-01-12
傳送門
題解
遇到求中位數,一般套路性的方法是二分答案,然後求出該數在區間內的排名,
但是此題稍微有點區別,區間大小不確定,所以我們用到一個更萬能的解決中位數問題的套路方法,
設<mid的數為-1,≥mid的數為1,得到b陣列,那麼若該區間的和S≥0,則該區間中位數≥mid,若S<0,則該區間中位數<mid;
對於的區間,首先區間內的值肯定得加上,然後,要讓中位數最大化,也就是讓S儘可能大,
所以還要加上內的最大字尾和內的最大字首,然後判斷S正負;
區間和、最大字首字尾可以用線段樹維護,這個簡單;
那麼b陣列怎麼求呢?把a陣列離散化後,總共有不超過n個mid,對於每個mid都有個不同的b陣列,
建n棵線段樹?時間空間都過不去;
考慮從到,可以發現只有排名為mid的數會從1變為-1,所以可以用主席樹求出每一棵樹,複雜度
查詢單次複雜度,所以總複雜度。
並不需要寫3種線段樹,因為線段樹內維護最大字首字尾時要用到區間和,所以你可以用一棵線段樹維護三個值,方便呼叫;
查詢函式也不需要分別寫3個,只需一個函式返回3個值,複雜度都一樣,並且這題常數要求並不苛刻(5625000*常數),常數大一點隨便過。
程式碼
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cmath> #include<queue> #include<vector> #include<map> #define ll long long #define MAXN 20005 using namespace std; inline ll read(){ ll x=0;bool f=1;char s=getchar(); while((s<'0'||s>'9')&&s>0){if(s=='-')f^=1;s=getchar();} while(s>='0'&&s<='9')x=(x<<1)+(x<<3)+s-'0',s=getchar(); return f?x:-x; } int n,q,IN,root[MAXN],in[5],id; ll a[MAXN],b[MAXN],ans; vector<int>c[MAXN]; struct itn{ int ls,rs,s,pr,su; itn(){} itn(int L,int R,int S,int P,int U){ ls=L,rs=R,s=S,pr=P,su=U; } }t[MAXN*20]; map<ll,int>mp; inline void build(int x,int l,int r){ if(l==r){t[x].s=t[x].pr=t[x].su=1;return;} int mid=(l+r)>>1; t[x].ls=++IN,t[x].rs=++IN; build(t[x].ls,l,mid),build(t[x].rs,mid+1,r); t[x].s=t[t[x].ls].s+t[t[x].rs].s; t[x].pr=max(t[t[x].ls].pr,t[t[x].ls].s+t[t[x].rs].pr); t[x].su=max(t[t[x].rs].su,t[t[x].rs].s+t[t[x].ls].su); } inline void add(int x,int y,int l,int r,int a){ if(l==r){t[x].s=t[x].pr=t[x].su=-1;return;} int mid=(l+r)>>1; if(a<=mid)t[x].ls=++IN,t[x].rs=t[y].rs,add(t[x].ls,t[y].ls,l,mid,a); else t[x].ls=t[y].ls,t[x].rs=++IN,add(t[x].rs,t[y].rs,mid+1,r,a); t[x].s=t[t[x].ls].s+t[t[x].rs].s; t[x].pr=max(t[t[x].ls].pr,t[t[x].ls].s+t[t[x].rs].pr); t[x].su=max(t[t[x].rs].su,t[t[x].rs].s+t[t[x].ls].su); } inline itn query(int x,int l,int r,int a,int b){ if(a>b)return itn(a,b,0,0,0); if(l==a&&r==b)return itn(a,b,t[x].s,t[x].pr,t[x].su); int mid=(l+r)>>1; if(a<=mid){ if(b>mid){ itn u=query(t[x].ls,l,mid,a,mid),v=query(t[x].rs,mid+1,r,mid+1,b); return itn(a,b,u.s+v.s,max(u.pr,u.s+v.pr),max(v.su,v.s+u.su)); } else return query(t[x].ls,l,mid,a,b); } else return query(t[x].rs,mid+1,r,a,b); } int main() { n=read(); for(int i=1;i<=n;i++)a[i]=read(),mp[a[i]]; map<ll,int>::iterator it; for(it=mp.begin();it!=mp.end();it++)b[++id]=it->first,it->second=id; for(int i=1;i<=n;i++)a[i]=mp[a[i]],c[a[i]].push_back(i); root[1]=++IN,build(IN,1,n); for(int i=2;i<=id;i++){ root[i]=root[i-1]; for(int j=0;j<c[i-1].size();j++){ int x=++IN; add(x,root[i],1,n,c[i-1][j]),root[i]=x; } } q=read(); while(q--){ for(int i=0;i<4;i++)in[i]=(read()+ans)%(1ll*n)+1; sort(in,in+4); int l=1; for(int i=15;i>=0;i--) if(l+(1<<i)<=id){ int o=l+(1<<i),sum=query(root[o],1,n,in[1]+1,in[2]-1).s; sum+=query(root[o],1,n,in[0],in[1]).su+query(root[o],1,n,in[2],in[3]).pr; if(sum>-1)l=o; } printf("%lld\n",ans=b[l]); } return 0; }