這題厲害啊。。。根本想不到。(據說是clj的題?)
首先要想到二分答案,想到就解出一半了。假設有乙個值x,如果x是區間[l,r]的中位數,且l∈[a,b],r∈[c,d],那麼答案一定》=x;否則答案一定
那麼如何判斷x是否是[l,r]的中位數呢?實際上,如果使用二分的話,我們不需要知道x是否一定是[l,r]的中位數,只要知道[l,r]中位數是否》=x即可。我們首先看一下如何判斷任意區間[u,v]的中位數是否》=x。
對於所有的數,如果我們將》=x的數令為1,
所以關鍵是如何構造出這樣的線段樹,因為x的數量太多了,為o(n),因此不可能構建n顆基於x的新的數列的線段樹。但是關鍵的是這些線段樹的大小形態是完全相同的,所以可以用主席樹的方式做。講到這差不多應該知道怎麼做了吧。
首先,這裡線段樹是以a[i]的值構造的,因此我們首先將a[i]排序。首先構造最小的a[i]的線段樹,我們構造一顆滿的線段樹。顯然所有的數都》=a[i],因此將基於a[i]的新的數列全部賦為1構造線段樹。
現在假設我們在構造第k小的a[x],而且第k-1小的是a[y]。注意到相對於基於a[y]的,在基於a[x]的新的數列中,只有第y個數從1變成了-1。但是萬一a[y]=a[x]怎麼辦?沒關係你會發現詢問的結果是一樣的。因此我們只需要將第y個數變成-1,因為隻變了1個數,所以只有logn個節點發生了變化,其餘節點乙個指標過去就行了。
那麼查詢就很簡單了。只需要判斷x對應的線段樹[a,b]的右連續最大子段和+[c,d]的左連續最大子段和+[b+1,c-1]的區間和是否》=0即可。
ac**如下(還是比較簡單的才2k):
#include#include#include#include#define n 200005
#define m 8000005
using namespace std;
struct nodea[n],val[m];
int n,m,trtot,rt[n],ls[m],rs[m];
void maintain(int k)
void build(int &k,int l,int r)
int mid=(l+r)>>1; build(ls[k],l,mid); build(rs[k],mid+1,r);
maintain(k);
}void ins(int l,int r,int x,int &y,int k,int v)
if (k<=mid)
else
maintain(y);
}node qry(int k,int l,int r,int x,int y)
}bool cmp(node aa,node bb)
int main()
sort(a+1,a+n+1,cmp); build(rt[1],1,n);
for (i=2; i<=n; i++) ins(1,n,rt[i-1],rt[i],a[i-1].y,-1);
scanf("%d",&m); int ans=0,ask[4],q[4];
while (m--)
sort(ask,ask+4); for (i=0; i<4; i++) q[i]=ask[i]+1;
int l=1,r=n+1; while (l+1>1; if (ok(mid,q[0],q[1],q[2],q[3])) l=mid; else r=mid; }
printf("%d\n",ans=a[l].x);
} return 0;
}
by lych
2016.2.12
BZOJ 2653 middle 二分 主席樹
乙個長度為n的序列a,設其排過序之後為b,其中位數定義為b n 2 其中a,b從0開始標號,除法取下整。給你乙個 長度為n的序列s。回答q個這樣的詢問 s的左端點在 a,b 之間,右端點在 c,d 之間的子串行中,最大的中位數。第一行序列長度n。接下來n行按順序給出a中的數。接下來一行q。然後q行每...
BZOJ2653 middle 主席樹 二分
無法確定中位數 我們可以考慮轉化思路。二分乙個中位數,再判斷是否合理。根據本題中中位數的定義,只需要小於 它的 數的個數 l en2 le 2len 我們可以將大於i ii的數賦值成1 11,小於的賦值成 1 1 1。若ma xlsu m a,b 1 sum b,c ma xrsu m c 1,d ...
bzoj2653 二分 主席樹
對於每乙個詢問二分答案。設當前答案為x,將 x的數的權值設為1,當 b 1,c 1 的權值和 a,b 權值和最大的字尾 c,d 權值和最大的字首 0時x可行。先對每個數離散,然後以每個值建立主席樹記錄區間和 最大字首 最大字尾就可以了。時間複雜度 o n log3n 1 include2 inclu...