1. 程式人生 > >LOJ #6279. 數列分塊入門 3-分塊(區間加法、查詢區間內小於某個值x的前驅(比其小的最大元素))

LOJ #6279. 數列分塊入門 3-分塊(區間加法、查詢區間內小於某個值x的前驅(比其小的最大元素))

posit head -c tar psu typedef small -h scu

#6279. 數列分塊入門 3

內存限制:256 MiB時間限制:1500 ms標準輸入輸出 題目類型:傳統評測方式:文本比較 上傳者: hzwer 提交提交記錄統計測試數據討論 3

題目描述

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

輸入格式

第一行輸入一個數字 nn。

第二行輸入 nn 個數字,第 ii 個數字為 a_iai?,以空格隔開。

接下來輸入 nn 行詢問,每行輸入四個數字 \mathrm{opt}opt、ll、rr、cc,以空格隔開。

\mathrm{opt} = 0opt=0,表示將位於 [l, r][l,r] 的之間的數字都加 cc。

\mathrm{opt} = 1opt=1,表示詢問 [l, r][l,r] 中 cc 的前驅的值(不存在則輸出 -11)。

輸出格式

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

樣例

樣例輸入

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

樣例輸出

3
-1

數據範圍與提示

對於 100\%100% 的數據,1 \leq n \leq 100000, -2^{31} \leq \mathrm{others}1n100000,231others、\mathrm{ans} \leq 2^{31}-1ans2311。

代碼:

  1 //#6279. 數列分塊入門 3-區間加法,查詢區間內小於某個值x的前驅(比其小的最大元素)
  2 #include<bits/stdc++.h>
  3 using namespace std;
  4 typedef long long ll;
  5 const int maxn=1e5+10;
  6 
  7 int n,m;
  8 ll a[maxn],b[maxn],pos[maxn],tag[maxn];
  9 
 10 void rechange(int x)
 11 {
 12     for(int i=(x-1
)*m+1;i<=min(x*m,n);i++){ 13 b[i]=a[i]; 14 } 15 sort(b+(x-1)*m+1,b+min(x*m,n)+1); 16 } 17 18 void update(int l,int r,ll c) 19 { 20 if(pos[l]==pos[r]){ 21 for(int i=l;i<=r;i++) 22 a[i]+=c; 23 rechange(pos[l]); 24 } 25 else{ 26 for(int i=l;i<=pos[l]*m;i++) 27 a[i]+=c; 28 rechange(pos[l]); 29 for(int i=pos[l]+1;i<=pos[r]-1;i++) 30 tag[i]+=c; 31 for(int i=(pos[r]-1)*m+1;i<=r;i++) 32 a[i]+=c; 33 rechange(pos[r]); 34 } 35 } 36 37 ll query(int l,int r,ll c) 38 { 39 ll ans=-1; 40 if(pos[l]==pos[r]){ 41 for(int i=l;i<=r;i++){ 42 if(a[i]+tag[pos[l]]<c){ 43 ans=max(ans,a[i]+tag[pos[l]]); 44 } 45 } 46 } 47 else{ 48 for(int i=l;i<=pos[l]*m;i++){ 49 if(a[i]+tag[pos[l]]<c){ 50 ans=max(ans,a[i]+tag[pos[l]]); 51 } 52 } 53 for(int i=pos[l]+1;i<=pos[r]-1;i++){ 54 int cnt=c-tag[i]; 55 int ret=lower_bound(b+(i-1)*m+1,b+i*m+1,cnt)-b-1; 56 //cout<<ret<<" "<<(i-1)*m<<endl; 57 if(ret!=(i-1)*m) 58 ans=max(ans,b[ret]+tag[i]); 59 } 60 for(int i=(pos[r]-1)*m+1;i<=r;i++){ 61 if(a[i]+tag[pos[r]]<c){ 62 ans=max(ans,a[i]+tag[pos[r]]); 63 } 64 } 65 } 66 return ans; 67 } 68 69 int main() 70 { 71 scanf("%d",&n); 72 m=sqrt(n); 73 for(int i=1;i<=n;i++){ 74 scanf("%d",&a[i]); 75 b[i]=a[i]; 76 pos[i]=(i-1)/m+1; 77 } 78 for(int i=1;i<=m+1;i++) 79 sort(b+(i-1)*m+1,b+min(i*m,n)+1); 80 for(int i=1;i<=n;i++){ 81 int op,l,r; 82 ll c; 83 scanf("%d%d%d%lld",&op,&l,&r,&c); 84 if(op==0){ 85 update(l,r,c); 86 } 87 else{ 88 printf("%lld\n",query(l,r,c)); 89 } 90 } 91 } 92 93 94 /* 95 10 96 1 3 4 2 5 7 11 3 5 1 97 0 1 5 1 98 1 1 7 2 99 0 3 9 1 100 1 4 8 7 101 1 1 10 6 102 1 3 5 3 103 1 5 10 7 104 1 6 10 6 105 1 2 7 4 106 1 2 7 5 107 108 -1 109 4 110 4 111 -1 112 6 113 4 114 -1 115 4 116 */

LOJ #6279. 數列分塊入門 3-分塊(區間加法、查詢區間內小於某個值x的前驅(比其小的最大元素))