1. 程式人生 > 實用技巧 >LibreOJ - 6279 數列分塊入門 3(塊內二分)

LibreOJ - 6279 數列分塊入門 3(塊內二分)

題目描述

給出一個長為n的數列,以及n個操作,操作涉及區間加法,詢問區間內小於某個值x的前驅(比其小的最大元素)。輸入格式

第一行輸入一個數字 。

第二行輸入n個數字,第i個數字為ai,以空格隔開。

接下來輸入n行詢問,每行輸入四個數字opt,l,r,c,以空格隔開。

若opt=0,表示將位於l,r的之間的數字都加c。

若opt=1,表示詢問l,r中,c的前驅的值(不存在則輸出 )。

輸出格式

對於每次詢問,輸出一行一個數字表示答案。

樣例

樣例輸入

4
1 2 2 3
0 1 3 1
1 1 4 4
0 1 2 2
1 1 2 4

樣例輸出

3
-1

和上一題類似,只不過是求區間條件最值。注意!上一題一通lower_bound操作最後得到的是偏移量,而上一題是求的元素個數,所以直接累加答案即可。而這個題得到的是數在b陣列的位置而非a陣列,ppos是b陣列的索引!沒注意到這點被坑慘了T^T

#include <bits/stdc++.h>
using namespace std;
int a[500005], b[500005], add[500005];  
int L[500005], R[500005];
int pos[500005];
int n, t;
inline int read(){   int s=0,w=1;   char ch=getchar();   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();   return
s*w;} void change(int l, int r, int d) { int p = pos[l], q = pos[r]; if (p == q) { for (int i = l; i <= r; i++) a[i] += d; for (int i = L[p]; i <= R[p]; i++) { a[i] += add[p]; b[i] = a[i]; } add[p] = 0; sort(b + L[p], b + R[p] + 1
); } else { for (int i = p + 1; i <= q - 1; i++) add[i] += d; for (int i = l; i <= R[p]; i++) a[i] += d; for (int i = L[p]; i <= R[p]; i++) { a[i] += add[p]; b[i] = a[i]; } add[p] = 0; sort(b + L[p], b + R[p] + 1); for (int i = L[q]; i <= r; i++) a[i] += d; for (int i = L[q]; i <= R[q]; i++) { a[i] += add[q]; b[i] = a[i]; } add[q] = 0; sort(b + L[q], b + R[q] + 1); } } int ask(int l, int r, int c) { int p = pos[l], q = pos[r], ans = -1; if (p == q) { for (int i = l; i <= r; i++) if (a[i] + add[p] < c) ans = max(ans, a[i] + add[p]); return ans; } else { for (int i = p + 1; i <= q - 1; i++) { int ppos = lower_bound(b + L[i], b + R[i] + 1, c - add[i]) - b;//查詢小於c的最大數 注意是b[ppos-1]而非a[ppos-1]! if(ppos > L[i]) ans = max(ans, b[ppos - 1] + add[i]); } for (int i = l; i <= R[p]; i++) if (a[i] + add[p] < c) ans = max(ans, a[i] + add[p]); for (int i = L[q]; i <= r; i++) if (a[i] + add[q] < c) ans = max(ans, a[i] + add[q]); return ans; } } int main() { cin >> n; memset(add, 0, sizeof(add)); for (int i = 1; i <= n; i++) { a[i] = read(); b[i] = a[i]; } t = sqrt(n); for (int i = 1; i <= t; i++) { L[i] = (i - 1) * sqrt(n) + 1; R[i] = i * sqrt(n); } if (R[t] < n) t++, L[t] = R[t - 1] + 1, R[t] = n; for (int i = 1; i <= t; i++) { for (int j = L[i]; j <= R[i]; j++) { pos[j] = i; } sort(b + L[i], b + R[i] + 1); } for (int i = 1; i <= n; i++) { int opt, l, r, c; opt = read(), l = read(), r = read(), c = read(); if (opt == 0) { change(l, r, c); } else { cout << ask(l, r, c) << endl; } } }