首先,看到中位數就應該會想到乙個經典做法,二分乙個\(mid\),把小於\(mid\)的數值為\(-1\),大於\(mid\)的數值為\(1\),如果這個區間的和\(>=0\)的話中位數可以更大,否則要更小
而題目中要求中位數最大,所以自然這個區間的和要越大越好,自然要多取\(1\)
我們知道\([b,c]\)這個區間是肯定會取到的,所以只要求和,而\([a,b-1],[c+1,d]\)這兩個區間乙個取最大字尾,乙個取最大字首,這樣就保證了中位數最大
但是每二分乙個\(mid\)就要重新把整個序列用\(-1,1\)代替,複雜度肯定承受不起,那怎麼辦呢,我們可以預處理每乙個數做\(mid\)時,每乙個區間最大字首,最大字尾,區間和,用線段樹來實現
但是對於每乙個數開一棵線段樹也是承受不起的,但是我們考慮到,如果我們按順序來列舉\(mid\)的時候(先排序離散),\(mid\)這個位置的線段樹,與\(mid+1\)這個位置的線段樹唯一的區別,就是離散後在\(mid\)這個位置的數由\(-1\)變為了\(1\),也就是說相鄰兩棵線段樹之間可以共用很多部分
立刻想到主席樹!
至於字尾字首爛大街的操作就不講了
下面是美滋滋的**時間~~~
#include#include#include#include#include#define n 20007
using namespace std;
struct tree
tr[n<<7];
int n,m,q,len,last,cnt;
int val1[n],val2[n],rt[n],qq[4];
vectorpos[n];
void pushup(int x)
void update(int &x,int l,int r,int p,int v)
if(pr)
return;
int mid=l+((r-l)>>1);
update(tr[x].ls,l,mid,p,v);
update(tr[x].rs,mid+1,r,p,v);
pushup(x);
//printf("ls:%d rs:%d\n",tr[x].sum,tr[x].lsum);
}int ask_sum(int x,int l,int r,int ll,int rr)
int ask_lsum(int x,int l,int r,int ll,int rr)
int ask_rsum(int x,int l,int r,int ll,int rr)
int main()
for(int i=1;i<=n;++i)
update(rt[len+1],1,n,i,-1);
for(int i=len;i;--i)
last=val2[l];
printf("%d\n",last);
} return 0;
}
國家集訓隊 middle
傳送門 按照中位數題的套路,二分答案 mid 序列中 ge mid 記為 1 mid 的記為 1 然後只要存在乙個區間 l,r l in a,b r in c,d 的和 ge 0 則答案可以更大,否則就更小。所以說我們就要算出區間 b 1,c 1 的和,加上 a,b 的最大字尾,還有 c,d 最大字...
國家集訓隊 middle
考慮二分答案,把問題轉化成可行性問題,然後發現b 1 c 1 是一定必選的,另外兩邊要想最大就是維護乙個連續最大子段和 然後每次二分值改變,只會影響線段樹上log個位置,於是考慮主席樹 includeusing namespace std inline intread while ch 0 ch 9...
國家集訓隊 middle
乙個長度為n的序列a,設其排過序之後為b,其中位數定義為b n 2 其中a,b從0開始標號,除法取下整。給你乙個長度為n的序列s。回答q個這樣的詢問 s的左端點在 a,b 之間,右端點在 c,d 之間的子串行中,最大的中位數。其中a位置也從0開始標號。第一行序列長度n。接下來n行按順序給出a中的數。...