BZOJ 2653 可持久化線段樹

2021-08-08 11:22:36 字數 2173 閱讀 9360

對於中位數有乙個性質,將所有大於等於他的數置為

1 , 小於他的數置為−1

,則所有數的和

0 或

1。單調性還是很顯然的,因此我們二分答案,若對陣列求和答案大於等於

0 ,則當前答案可行。

定長的區間我們已經會求解中位數了,現在的問題是,左端點在[l

1,r1

],右端點在[l

2,r2

] , 如何找到中位數。此時我們二分乙個答案,將陣列所有數按之前的規則變成

1 ,−1

。 會發現若上述」左端點不固定的若干區間」 + 「定區間」 + 「右端點不定的若干區間」組成的新區間的最大子段和大於等於

0 ,則我們二分出的答案必然是某個區間的中位數。

二分答案,以及如何判定這個答案是否滿足每個詢問區間的方法我們已經知道了。

現在的問題就是,如何快速得到乙個區間的最大子段和,這是乙個經典的線段樹問題。

其實我們還剩下最後乙個問題,每次二分出乙個答案,所有陣列都在變化,總不能每個詢問都建立log個線段樹。

其實只要想一下就會發現,這題中出現的陣列的種類只有n+

1種(初始所有數都是

1 ,每次插入乙個數,都一定會使這個陣列中比他小的數變成−1

)。如果從小到大插入數的話,其實相對上一次插入只會使得乙個數變化。因此可以考慮用可持久化線段樹來完成動態修改過程。

複雜度o(n

logn

logn

) .

#include 

#define all(x) x.begin(), x.end()

using namespace std;

const int maxn = 22000;

int n, cid;

int val[maxn];

vectorint, int> > v;

struct seg tr[maxn*40];

int root[maxn];

int ans = 0;

void pushup(int

x) int build(int l, int r)

intm = l + r >> 1;

tr[x].l = build(l, m);

tr[x].r = build(m+1, r);

pushup(x);

returnx;}

int update(int

y, int l, int r, int

pos, int val)

intm = l + r >> 1;

if(pos

<= m) else

pushup(x);

returnx;}

int ask(int l, int r, int l, int r, int

x) int

m = (l + r) >> 1;

int res = 0;

if(l <= m)

res += ask(l, r, l, m, tr[x].l);

if(r > m)

res += ask(l, r, m+1, r, tr[x].r);

return res;

}int askl(int l, int r, int l, int r, int

x) int askr(int l, int r, int l, int r, int

x) void init()

bool check(int

x, int l1, int r1, int l2, int r2)

int main() );

}sort(all(v));

root[0] = build(0, n-1);

for(int i = 1; i <= n; i++)

root[i] = update(root[i-1], 0, n-1, v[i-1].second, -1);

intq; scanf("%d", &q);

while(q--)

sort(all(tp));

int l = 1, r = n + 1, m;

while(l < r)

printf("%d\n", ans = v[l-1].first);

}return

0;}

可持久化線段樹總結(可持久化線段樹,線段樹)

最近正在學習一種資料結構 可持久化線段樹。看了網上的許多部落格,弄了幾道模板題,思路有點亂了,所以還是來總結整理下吧。你需要維護這樣的乙個長度為 n 的陣列,支援如下幾種操作 在某個歷史版本上修改某乙個位置上的值 訪問某個歷史版本上的某一位置的值 此外,每進行一次操作 對於操作2,即為生成乙個完全一...

bzoj2653 二分 主席樹

對於每乙個詢問二分答案。設當前答案為x,將 x的數的權值設為1,當 b 1,c 1 的權值和 a,b 權值和最大的字尾 c,d 權值和最大的字首 0時x可行。先對每個數離散,然後以每個值建立主席樹記錄區間和 最大字首 最大字尾就可以了。時間複雜度 o n log3n 1 include2 inclu...

可持久化線段樹

可持久化線段樹,意思是可以查詢歷史記錄的線段樹。又叫主席樹。我們可以通過記錄不同的根節點,並在每乙個更新到的節點處新建必要的節點。詢問不同版本的主席樹,只需要進入不同的根節點即可。例題 給定n,m,輸入n個數組成的數列,有m個詢問,每次詢問l,r這個區間中,第k小的數的值。分析 這個題可以巧妙運用主...