【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
", 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
", 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
", lastans);
}
}
/*
5
2 4 1 5 3
1
3 1 0 2
*/