【CF-484E】Sign on Fence && 【luogu-P2839】[國家集訓隊]middle (二分+主席樹的妙用整理)
阿新 • • 發佈:2020-11-23
【CF-484E】Sign on Fence 題目連結:https://codeforces.ml/contest/484/problem/E
【luogu-P2839】[國家集訓隊]middle 題目連結:https://www.luogu.com.cn/problem/P2839
思路
這兩道題都應用了一個思想:將小於(等於)其值的數的位置和大於其值的位置分開討論。
具體可以在這兩行程式碼實現:
for (int i = 1; i <= n; i++) { vec[h[i]].push_back(i); } root[0] = tree.build(1, n); for (int i = 1; i <= Discrete::blen; i++) { root[i] = root[i-1]; for (auto e: vec[i]) { root[i] = tree.update(root[i], e, 0, 1, n); }
【CF-484E】Sign on Fence 具體思路
二分答案,將值大於二分出來的 \(mid\) 的位置置為 \(1\),檢查在區間連續範圍內是否有一段長度為 \(k\)。
【CF-484E】Sign on Fence AC程式碼
#include <bits/stdc++.h> using namespace std; const int MAXN = 1e5 + 5; namespace Discrete { // 祖傳離散化 int b[MAXN], blen, btol; void insert(int x) { b[btol++] = x; } void init() { sort(b, b + btol); blen = unique(b, b + btol) - b; } int val2id(int x) { return lower_bound(b, b + blen, x) - b + 1; } int id2val(int x) {return b[x-1];} } using Discrete::val2id; using Discrete::id2val; class HJT { public: struct node { int ch[2]; int pre, suf, len; node() { ch[0] = ch[1] = pre = suf = len = 0; } } T[MAXN*70]; int tot = 0; #define lson T[rt].ch[0] #define rson T[rt].ch[1] inline void push_up(int rt, int be, int en) { T[rt].pre = T[lson].pre, T[rt].suf = T[rson].suf; T[rt].len = max(T[lson].suf + T[rson].pre, max(T[lson].len, T[rson].len)); int mid = (be + en) >> 1; if (T[lson].pre == mid-be+1) T[rt].pre += T[rson].pre; if (T[rson].suf == en- (mid+1) + 1) T[rt].suf += T[lson].suf; } int build(int l, int r) { int nrt = ++tot; if (l == r) { T[nrt].len = T[nrt].pre = T[nrt].suf = 1; return nrt; } int mid = (l + r) >> 1; T[nrt].ch[0] = build(l, mid), T[nrt].ch[1] = build(mid + 1, r); push_up(nrt, l, r); return nrt; } int update(int rt, int pos, int v, int be, int en) { int nrt = ++tot; if (be == en) { T[nrt].len = T[nrt].pre = T[nrt].suf = v; return nrt; } int mid = (be + en) >> 1; if (pos <= mid) { T[nrt].ch[0] = update(lson, pos, v, be, mid); T[nrt].ch[1] = rson; } else { T[nrt].ch[0] = lson; T[nrt].ch[1] = update(rson, pos, v, mid + 1, en); } push_up(nrt, be, en); return nrt; } node query_max(int rt, int L, int R, int be, int en) { if (L <= be && en <= R) return T[rt]; int mid = (be + en) >> 1; if (R <= mid) return query_max(lson, L, R, be, mid); else if (L > mid) return query_max(rson, L, R, mid+1, en); else { node ans; node ansl = query_max(lson, L, R, be, mid); node ansr = query_max(rson, L, R, mid+1, en); ans.pre = ansl.pre, ans.suf = ansr.suf; ans.len = max(ansl.suf + ansr.pre, max(ansl.len, ansr.len)); if (ansl.pre == mid - be + 1) ans.pre += ansr.pre; if (ansr.suf == en - (mid+1) + 1) ans.suf += ansl.suf; return ans; } } }tree; int h[MAXN], root[MAXN]; vector<int> vec[MAXN]; int n; bool check(int mid, int l, int r, int k) { // printf("%d\n", tree.query_max(root[mid-1], l, r, 1, n).len); if (tree.query_max(root[mid-1], l, r, 1, n).len >= k) return 1; else return 0; } int main() { scanf("%d", &n); Discrete::btol = 0; for (int i = 1; i <= n; i++) scanf("%d", &h[i]), Discrete::insert(h[i]); Discrete::init(); for (int i = 1; i <= n; i++) h[i] = val2id(h[i]); for (int i = 1; i <= n; i++) { vec[h[i]].push_back(i); } root[0] = tree.build(1, n); for (int i = 1; i <= Discrete::blen; i++) { root[i] = root[i-1]; for (auto e: vec[i]) { root[i] = tree.update(root[i], e, 0, 1, n); } } int m; scanf("%d", &m); while (m--) { int l, r, k; scanf("%d%d%d", &l, &r, &k); int L = 1, R = Discrete::blen; while (L < R) { int mid = (L+R+1)>>1; if (check(mid,l,r, k)) L = mid; else R = mid-1; } printf("%d\n", id2val(L)); } } /* 10 1 2 3 4 5 6 7 8 9 10 1 2 7 5 */
【luogu-P2839】[國家集訓隊]middle 具體思路
二分列舉中位數,應用到具體的性質為:如果一段數將大於 \(mid\) 的數賦為 \(-1\),小於 \(mid\) 的數賦值為 \(1\),那麼和 \(= 0\) 的話,那麼則可取。
再在查詢的範圍內尋找字首和字尾最大的和,若和 \(\geq 0\),則代表這段序列可以通過縮小來使得最終的和 \(= 0\)。
【luogu-P2839】[國家集訓隊]middle AC程式碼
#include <bits/stdc++.h> #define inf 0x3f3f3f3f #define pb push_back using namespace std; const int MAXN = 2e4 + 5; namespace Discrete { // 祖傳離散化 int b[MAXN << 1], btol, blen; void insert(int x) { b[btol++] = x; } void init() { sort(b, b + btol); blen = unique(b, b + btol) - b; } int val2id(int x) { return lower_bound(b, b + blen, x) - b + 1; } int id2val(int x) { return b[x - 1]; } } using Discrete::val2id; using Discrete::id2val; class HJT { public: struct node { int ch[2]; int pre, suf, sum; node() { ch[0] = ch[1] = pre = suf = sum = 0; } } T[MAXN * 70]; int tot; #define lson T[rt].ch[0] #define rson T[rt].ch[1] inline void push_up(int rt) { T[rt].sum = T[lson].sum + T[rson].sum; T[rt].pre = max(T[lson].pre, T[lson].sum + T[rson].pre); T[rt].suf = max(T[rson].suf, T[rson].sum + T[lson].suf); } int build(int l, int r) { int nrt = ++tot; if (l == r) { T[nrt].sum = T[nrt].pre = T[nrt].suf = 1; return nrt; } int mid = (l + r) >> 1; T[nrt].ch[0] = build(l, mid), T[nrt].ch[1] = build(mid + 1, r); push_up(nrt); return nrt; } int update(int rt, int pos, int v, int be, int en) { int nrt = ++tot; if (be == en) { T[nrt].sum = T[nrt].pre = T[nrt].suf = v; return nrt; } int mid = (be + en) >> 1; if (pos <= mid) { T[nrt].ch[0] = update(lson, pos, v, be, mid); T[nrt].ch[1] = rson; } else { T[nrt].ch[0] = lson; T[nrt].ch[1] = update(rson, pos, v, mid + 1, en); } push_up(nrt); return nrt; } int query_sum(int rt, int L, int R, int be, int en) { if (L <= be && en <= R) return T[rt].sum; int mid = (be + en) >> 1; int ans = 0; if (L <= mid) ans += query_sum(lson, L, R, be, mid); if (R > mid) ans += query_sum(rson, L, R, mid + 1, en); return ans; } node query_pre(int rt, int L, int R, int be, int en) { if (L <= be && en <= R) return T[rt]; int mid = (be + en) >> 1; if (R <= mid) return query_pre(lson, L, R, be, mid); else if (L > mid) return query_pre(rson, L, R, mid + 1, en); else { node ans; node ansl = query_pre(lson, L, R, be, mid); node ansr = query_pre(rson, L, R, mid + 1, en); ans.sum = ansl.sum + ansr.sum; ans.pre = max(ansl.pre, ansl.sum + ansr.pre); return ans; } } node query_suf(int rt, int L, int R, int be, int en) { if (L <= be && en <= R) return T[rt]; int mid = (be + en) >> 1; if (R <= mid) return query_suf(lson, L, R, be, mid); else if (L > mid) return query_suf(rson, L, R, mid + 1, en); else { node ans; node ansl = query_suf(lson, L, R, be, mid); node ansr = query_suf(rson, L, R, mid + 1, en); ans.sum = ansl.sum + ansr.sum; ans.suf = max(ansr.suf, ansr.sum + ansl.suf); return ans; } } } tree; int a[MAXN], root[MAXN]; vector<int> vec[MAXN]; int n; bool check(int mid, const vector<int> &q) { int sum = 0; if (q[1] + 1 <= q[2] - 1) sum = tree.query_sum(root[mid - 1], q[1] + 1, q[2] - 1, 1, n); sum += tree.query_suf(root[mid - 1], q[0], q[1], 1, n).suf; sum += tree.query_pre(root[mid - 1], q[2], q[3], 1, n).pre; if (sum >= 0) return 1; else return 0; } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); Discrete::insert(a[i]); } Discrete::init(); for (int i = 1; i <= n; i++) a[i] = val2id(a[i]); for (int i = 1; i <= n; i++) { vec[a[i]].pb(i); } root[0] = tree.build(1, n); for (int i = 1; i <= Discrete::blen; i++) { root[i] = root[i - 1]; for (auto e: vec[i]) { root[i] = tree.update(root[i], e, -1, 1, n); } } int m; scanf("%d", &m); int lastans = 0; while (m--) { vector<int> q(4); scanf("%d%d%d%d", &q[0], &q[1], &q[2], &q[3]); for (int i = 0; i < 4; i++) q[i] = (q[i] + lastans) % n + 1; sort(q.begin(), q.end()); int L = 1, R = Discrete::blen; while (L < R) { int mid = (L + R + 1) >> 1; if (check(mid, q)) L = mid; else R = mid - 1; } lastans = id2val(L); printf("%d\n", lastans); } } /* 5 2 4 1 5 3 1 3 1 0 2 */