傳送門
按照中位數題的套路,二分答案 \(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中的數。...