日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

[BZOJ2653]middle

發布時間:2023/11/27 生活经验 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [BZOJ2653]middle 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

[BZOJ2653]middle

題面

一個長度為n的序列a,設其排過序之后為b,其中位數定義為b[n/2],其中a,b從0開始標號,除法取下整。給你一個

長度為n的序列s?;卮餛個這樣的詢問: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]?! ?/p>

輸入保證滿足條件。

第一行所謂“排過序”指的是從小到大排序!

n<=20000,Q<=25000

Output

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

Sample Input

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

Sample Output

271451044
271451044
969056313

思路

這道題也是蠻有意思的。我們思考一下,對于單次查詢該怎么做。

這里有一個針對中位數的數據結構題的小trick:把大于x的設置為1,小于x的設置為-1,等于x的設置為0。很顯然,如果\(sum\)大于0則中位數比x更大,小于0則中位數比x更小,等于0則中位數為x。(在這道題中我們可以把\(sum\)為0的情況歸類到中位數大于x里面,原因下面會說)

有了上面這個小trick,我們就可以判斷任何一個數和中位數的關系。那么很顯然這里可以使用二分。那么問題來了,二分的復雜度是\(O(\log n)\),如果我們對于每一次二分都重新求和,復雜度是\(O(n)\),對于q次查詢,總復雜度為\(O(qn\log n)\),很顯然是要炸的。

我們發現復雜度里的\(O(q \log n)\)是不能省的(強制在線的查詢和二分),那我們就要試圖做到\(\log n\)判斷一個數是否為中位數。

我們發現,在二分尋找中位數時,不是每一次判斷都需要修改全樹的。在每次縮小查詢范圍后(l或r變為mid),范圍外的數和下一次二分的數的大小關系是始終不變的,所以我們可以繼承上一次修改的結果而不需要再次修改。

另外,對于這種多次查詢又是強制在線的數據結構題,我們可以把所有潛在答案計算出來,再用可持久化數據結構儲存。

那么整理一下思路,解法如下:

  1. 先構建一個可持久化線段樹,每個葉子節點對應一個序列上的位置,節點初始值為1(畢竟最開始二分的值是無限小)。
  2. 按照從小到大的順序加入元素(值為-1)。每加入一次就相當于現在中位數可能的值增加。
  3. 對于每次查詢,我們可以用線段樹操作\(maxl(a,b)+sum(b,c)+maxr(c,d)\)來求得中位數的“判定值”。
  4. 對于每次查詢,二分一下答案對應的版本即可。

代碼

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define maxn (int)(2e4+1000)
#define ll long long
using namespace std;
int n,q,idx;
ll sum[maxn<<5],lmax[maxn<<5],rmax[maxn<<5];
int ls[maxn<<5],rs[maxn<<5],rt[maxn],pre,b[7];
struct gg{int num,loc;
}a[maxn];
void push_up(int x){sum[x]=sum[ls[x]]+sum[rs[x]];lmax[x]=max(sum[ls[x]]+lmax[rs[x]],lmax[ls[x]]);rmax[x]=max(sum[rs[x]]+rmax[ls[x]],rmax[rs[x]]);return;
}
int build(int l,int r){int now=++idx;if(l==r){sum[now]=lmax[now]=rmax[now]=1;return now;}int mid=(l+r)>>1;ls[now]=build(l,mid);rs[now]=build(mid+1,r);push_up(now);return now;
}
bool cop(gg x,gg y){return x.num<y.num;}int update(int last,int l,int r,int tar,int val){int now=++idx;lmax[now]=lmax[last]-2,rmax[now]=rmax[last]-2,sum[now]=sum[last]-2;ls[now]=ls[last],rs[now]=rs[last];if(l==r){return now;}int mid=(l+r)>>1;if(tar<=mid)ls[now]=update(ls[last],l,mid,tar,val);else{rs[now]=update(rs[last],mid+1,r,tar,val);}push_up(now);return now;
}
ll get_sum(int now,int l,int r,int tl,int tr){if(tl<=l&&r<=tr)return sum[now];int mid=(l+r)>>1;ll ans=0;if(tl<=mid)ans+=get_sum(ls[now],l,mid,tl,tr);if(tr>=mid+1)ans+=get_sum(rs[now],mid+1,r,tl,tr);return ans;
}
ll get_rmax(int now,int l,int r,int tl,int tr){if(r<l)return 0;int mid=(l+r)>>1;if(tl<=l&&r<=tr)return rmax[now];if(tr<=mid)return get_rmax(ls[now],l,mid,tl,tr);if(tl>=mid+1)return get_rmax(rs[now],mid+1,r,tl,tr);return max(get_sum(rs[now],mid+1,r,tl,tr)+get_rmax(ls[now],l,mid,tl,tr),get_rmax(rs[now],mid+1,r,tl,tr));
}
ll get_lmax(int now,int l,int r,int tl,int tr){if(r<l)return 0;int mid=(l+r)>>1;if(tl<=l&&r<=tr)return lmax[now];if(tr<=mid)return get_lmax(ls[now],l,mid,tl,tr);if(tl>=mid+1)return get_lmax(rs[now],mid+1,r,tl,tr);return max(get_sum(ls[now],l,mid,tl,tr)+get_lmax(rs[now],mid+1,r,tl,tr),get_lmax(ls[now],l,mid,tl,tr));
}
bool check(int ves){ves-=1;ves=rt[ves];llans=get_sum(ves,1,n,b[2],b[3])+max(get_rmax(ves,1,n,b[1],b[2]-1),0ll)+max(0ll,get_lmax(ves,1,n,b[3]+1,b[4]));if(ans>=0)return 1;else return 0;
}
int main(){
//  freopen("in","r",stdin);scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&a[i].num),a[i].loc=i;rt[0]=build(1,n);sort(a+1,a+1+n,cop);for(int i=1;i<=n;i++){rt[i]=update(rt[i-1],1,n,a[i].loc,-2);}scanf("%d",&q);for(int i=1;i<=q;i++){for(int j=1;j<=4;j++){scanf("%d",&b[j]);b[j]=(b[j]+pre)%n;b[j]++;}sort(b+1,b+5);int l=0,r=n;while(l<r){int mid=(l+r+1)>>1;if(check(mid)){l=mid;}else{r=mid-1;}}printf("%d\n",a[l].num);pre=a[l].num;}return 0;
}

轉載于:https://www.cnblogs.com/GavinZheng/p/10862793.html

總結

以上是生活随笔為你收集整理的[BZOJ2653]middle的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。