P5356 [Ynoi2017] 由乃打扑克
题目链接
思路:
实现两个操作,区间加法和查询区间第k大。考虑分块的做法,区间加法对整块来说可以直接另开一个数组\(tag\)来对整块进行区间加法,对于零散块就直接暴力的加上。
区间加法
void update(int l, int r, i64 x) {
if (belong[l] == belong[r]) {
for (int i = l; i <= r; i++ )
a[i] += x;
for (int i = bln[belong[l]], bel = belong[l]; i <= brn[bel]; i++ ) {
b[i] = a[i];
}
std::sort(b + bln[belong[l]], b + brn[belong[l]] + 1);
return ;
}
for (int i = l, bel = belong[l]; i <= brn[bel]; i++ ) {
a[i] += x;
}
for (int i = bln[belong[r]], bel = belong[r]; i <= r; i++ ) {
a[i] += x;
}
for (int i = bln[belong[l]], bel = belong[l]; i <= brn[bel]; i++ ) {
b[i] = a[i];
}
for (int i = bln[belong[r]], bel = belong[r]; i <= brn[bel]; i++ ) {
b[i] = a[i];
}
std::sort(b + bln[belong[l]], b + brn[belong[l]] + 1);
std::sort(b + bln[belong[r]], b + brn[belong[r]] + 1);
for (int i = belong[l] + 1; i < belong[r]; i++ ) {
tag[i] += x;
}
}
\(1.\)块内最大的元素小于\(mid\)
\(2.\)块内最小的元素大于\(mid\)
\(3.\)块内最大的元素大于\(mid\),块内最小的元素小于\(mid\),对于这种情况我们二分处理。
查询区间第$k$大
i64 check(int l, int r, i64 x) {
i64 cnt = 0;
if (belong[l] == belong[r]) {
for (int i = l; i <= r; i++ ) {
cnt += (a[i] + tag[belong[i]] <= x);
}
return cnt;
}
for (int i = belong[l] + 1; i < belong[r]; i++ ) {
if (b[bln[i]] + tag[i] > x) continue;
if (b[brn[i]] + tag[i] <= x) {
cnt += brn[i] - bln[i] + 1;
continue;
}
int ln = bln[i], rn = brn[i];
while(ln < rn) {
int mid = (ln + rn + 1) >> 1;
if (b[mid] + tag[i] <= x) ln = mid;
else rn = mid - 1;
}
if (b[ln] + tag[i] <= x) cnt += ln - bln[i] + 1;
}
for (int i = l, bel = belong[l]; i <= brn[bel]; i++ ) {
if (a[i] + tag[bel] <= x) cnt ++;
}
for (int i = bln[belong[r]], bel = belong[r]; i <= r; i++ ) {
if (a[i] + tag[bel] <= x) cnt ++;
}
return cnt;
}
int query(int l, int r, int k) {
if (k < 1 || k > r - l + 1) return -1;
int ans = -1;
i64 ln = MIN(l, r);
i64 rn = MAX(l, r);
while(ln <= rn) {
i64 mid = (ln + rn) >> 1;
if (check(l, r, mid) < k) ln = mid + 1;
else rn = mid - 1, ans = mid;
}
return ans;
}
全部的代码:
constexpr int N = 1000010;
constexpr int M = 150;
int n, m;
int bln[N], brn[N], belong[N];
i64 tag[N];
i64 a[N], b[N];
void update(int l, int r, i64 x) {
if (belong[l] == belong[r]) {
for (int i = l; i <= r; i++ )
a[i] += x;
for (int i = bln[belong[l]], bel = belong[l]; i <= brn[bel]; i++ ) {
b[i] = a[i];
}
std::sort(b + bln[belong[l]], b + brn[belong[l]] + 1);
return ;
}
for (int i = l, bel = belong[l]; i <= brn[bel]; i++ ) {
a[i] += x;
}
for (int i = bln[belong[r]], bel = belong[r]; i <= r; i++ ) {
a[i] += x;
}
for (int i = bln[belong[l]], bel = belong[l]; i <= brn[bel]; i++ ) {
b[i] = a[i];
}
for (int i = bln[belong[r]], bel = belong[r]; i <= brn[bel]; i++ ) {
b[i] = a[i];
}
std::sort(b + bln[belong[l]], b + brn[belong[l]] + 1);
std::sort(b + bln[belong[r]], b + brn[belong[r]] + 1);
for (int i = belong[l] + 1; i < belong[r]; i++ ) {
tag[i] += x;
}
}
i64 MAX(int l, int r) {
i64 res = std::numeric_limits<int>::min();
if (belong[l] == belong[r]) {
for (int i = l; i <= r; i ++ )
res = std::max(res, a[i] + tag[belong[l]]);
return res;
}
for (int i = belong[l] + 1; i < belong[r]; i++ ) {
res = std::max(res, b[brn[i]] + tag[i]);
}
for (int i = bln[belong[r]], bel = belong[r]; i <= r; i++ ) {
res = std::max(res, a[i] + tag[bel]);
}
for (int i = l, bel = belong[l]; i <= brn[bel]; i++ ) {
res = std::max(res, a[i] + tag[bel]);
}
return res;
}
i64 MIN(int l, int r) {
i64 res = std::numeric_limits<int>::max();
if (belong[l] == belong[r]) {
for (int i = l; i <= r; i ++ )
res = std::min(res, a[i] + tag[belong[l]]);
return res;
}
for (int i = belong[l] + 1; i < belong[r]; i++ ) {
res = std::min(res, b[bln[i]] + tag[i]);
}
for (int i = bln[belong[r]], bel = belong[r]; i <= r; i++ ) {
res = std::min(res, a[i] + tag[bel]);
}
for (int i = l, bel = belong[l]; i <= brn[bel]; i++ ) {
res = std::min(res, a[i] + tag[bel]);
}
return res;
}
i64 check(int l, int r, i64 x) {
i64 cnt = 0;
if (belong[l] == belong[r]) {
for (int i = l; i <= r; i++ ) {
cnt += (a[i] + tag[belong[i]] <= x);
}
return cnt;
}
for (int i = belong[l] + 1; i < belong[r]; i++ ) {
if (b[bln[i]] + tag[i] > x) continue;
if (b[brn[i]] + tag[i] <= x) {
cnt += brn[i] - bln[i] + 1;
continue;
}
int ln = bln[i], rn = brn[i];
while(ln < rn) {
int mid = (ln + rn + 1) >> 1;
if (b[mid] + tag[i] <= x) ln = mid;
else rn = mid - 1;
}
if (b[ln] + tag[i] <= x) cnt += ln - bln[i] + 1;
}
for (int i = l, bel = belong[l]; i <= brn[bel]; i++ ) {
if (a[i] + tag[bel] <= x) cnt ++;
}
for (int i = bln[belong[r]], bel = belong[r]; i <= r; i++ ) {
if (a[i] + tag[bel] <= x) cnt ++;
}
return cnt;
}
int query(int l, int r, int k) {
if (k < 1 || k > r - l + 1) return -1;
int ans = -1;
i64 ln = MIN(l, r);
i64 rn = MAX(l, r);
while(ln <= rn) {
i64 mid = (ln + rn) >> 1;
if (check(l, r, mid) < k) ln = mid + 1;
else rn = mid - 1, ans = mid;
}
return ans;
}
signed main() {
std::cin.tie(nullptr)->sync_with_stdio(false);
std::cin >> n >> m;
for (int i = 1; i <= n; i ++ ) {
std::cin >> a[i];
b[i] = a[i];
belong[i] = (i - 1) / M + 1;
}
int lim = std::ceil(n * 1.0 / M);
for (int i = 1; i <= lim; i ++ ) {
bln[i] = (i - 1) * M + 1, brn[i] = i * M;
}
brn[lim] = n;
for (int i = 1; i <= lim; i++ )
std::sort(b + bln[i], b + brn[i] + 1);
for (int i = 0; i < m; i++ ) {
int op, l, r, k;
std::cin >> op >> l >> r >> k;
if (op == 1) std::cout << query(l, r, k) << "\n";
else update(l, r, k);
}
return 0 ^ 0;
}

浙公网安备 33010602011771号