國家集訓隊 middle

2022-05-02 02:18:09 字數 1533 閱讀 6873

傳送門

按照中位數題的套路,二分答案 \(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]\) 最大字首,加起來就是我們用來 \(check\) 的值。

這些過程可以用線段樹來搞,具體維護細節就和維護區間最大子段和差不多。

但是我們面臨另乙個問題:\(mid\) 會變,也就是我們的序列是會變的,我們不可能對於每乙個 \(mid\) 都建一棵線段樹。

那能不能用主席樹優化空間呢?

我們發現,\(mid\) 擴大 \(1\) ,只會有乙個數的值從 \(1\) 變成 \(-1\) ,也就是說我們只需要修改一條鏈上的資訊,這顯然可以用主席樹來搞,空間問題也就解決了。

參考**:

#include #include #define rg register

#define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout)

using namespace std;

template < class t > inline void read(t& s)

typedef long long ll;

const int _ = 20005;

int n, m, q[5], a[_], id[_], tot, rt[_];

struct node t[_ << 5];

inline void pushup(int p)

inline void build(int& p, int l = 1, int r = n)

int mid = (l + r) >> 1;

build(t[p].lc, l, mid), build(t[p].rc, mid + 1, r), pushup(p);

}inline void update(int& p, int q, int x, int l = 1, int r = n)

int mid = (l + r) >> 1;

if (x <= mid) update(t[p].lc, t[q].lc, x, l, mid);

else update(t[p].rc, t[q].rc, x, mid + 1, r);

pushup(p);

}inline node query(int ql, int qr, int p, int l = 1, int r = n) ;

}inline bool check(int mid)

inline bool cmp(int i, int j)

int main()

printf("%d\n", ans);

}return 0;

}

國家集訓隊 middle

考慮二分答案,把問題轉化成可行性問題,然後發現b 1 c 1 是一定必選的,另外兩邊要想最大就是維護乙個連續最大子段和 然後每次二分值改變,只會影響線段樹上log個位置,於是考慮主席樹 includeusing namespace std inline intread while ch 0 ch 9...

國家集訓隊 middle

首先,看到中位數就應該會想到乙個經典做法,二分乙個 mid 把小於 mid 的數值為 1 大於 mid 的數值為 1 如果這個區間的和 0 的話中位數可以更大,否則要更小 而題目中要求中位數最大,所以自然這個區間的和要越大越好,自然要多取 1 我們知道 b,c 這個區間是肯定會取到的,所以只要求和,...

國家集訓隊 middle

乙個長度為n的序列a,設其排過序之後為b,其中位數定義為b n 2 其中a,b從0開始標號,除法取下整。給你乙個長度為n的序列s。回答q個這樣的詢問 s的左端點在 a,b 之間,右端點在 c,d 之間的子串行中,最大的中位數。其中a位置也從0開始標號。第一行序列長度n。接下來n行按順序給出a中的數。...