LOJ #6279. 數列分塊入門 3
阿新 • • 發佈:2018-12-04
\(\color{#0066ff}{題目描述}\)
給出一個長為 n 的數列,以及 n 個操作,操作涉及區間加法,詢問區間內小於某個值 x 的前驅(比其小的最大元素)。
\(\color{#0066ff}{輸入格式}\)
第一行輸入一個數字 n。
第二行輸入 n 個數字,第 i 個數字為 \(a_i\),以空格隔開。
接下來輸入 n 行詢問,每行輸入四個數字 \(\mathrm{opt}、l、r、c\),以空格隔開。
若 \(\mathrm{opt} = 0\),表示將位於 \([l,r]\) 的之間的數字都加 c。
若 \(\mathrm{opt} = 1\),表示詢問 \([l,r]\)
\(\color{#0066ff}{輸出格式}\)
對於每次詢問,輸出一行一個數字表示答案。
\(\color{#0066ff}{輸入樣例}\)
4
1 2 2 3
0 1 3 1
1 1 4 4
0 1 2 2
1 1 2 4
\(\color{#0066ff}{輸出樣例}\)
3
-1
\(\color{#0066ff}{題解}\)
開一個數組記錄序列,保證塊內有序
對於區間加,如果是整塊,打標記,因為相對大小不變,所以不用管陣列
如果是散塊,暴力修改,同時改變陣列,並重新排序
對於詢問,初始定為極小值
對於整塊,直接lowerbound-1找到區間內的前驅
注意,如果找不到,返回的是l-1,所以特盤返回極小值
因為找的時候無法讓整個序列加上標記,所以lowerbound的時候要找x-標記
最後返回答案的時候要把標記加上
#include<cstdio> #include<queue> #include<vector> #include<iostream> #include<cstring> #include<algorithm> #include<cctype> #include<cmath> #define _ 0 #define LL long long #define Space putchar(' ') #define Enter putchar('\n') #define fuu(x,y,z) for(int x=(y),x##end=z;x<=x##end;x++) #define fu(x,y,z) for(int x=(y),x##end=z;x<x##end;x++) #define fdd(x,y,z) for(int x=(y),x##end=z;x>=x##end;x--) #define fd(x,y,z) for(int x=(y),x##end=z;x>x##end;x--) #define mem(x,y) memset(x,y,sizeof(x)) #ifndef olinr inline char getc() { static char buf[100001],*p1=buf,*p2=buf; return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100001,stdin),p1==p2)? EOF:*p1++; } #else #define getc() getchar() #endif template<typename T>inline void in(T &x) { int f=1; char ch; x=0; while(!isdigit(ch=getc()))(ch=='-')&&(f=-f); while(isdigit(ch)) x=x*10+(ch^48),ch=getc(); x*=f; } const int inf=0x7fffffff; struct K { int l,r,tag; K() {l=inf,r=-inf;} }e[150505]; struct seq { int val,bel; }a[105050]; int s[105050]; int n,num; inline int lob(int l,int r,int c,int p) { int t=std::lower_bound(s+l,s+r+1,c)-s-1; if(t==l-1) return -inf; return s[t]+e[p].tag; } inline void init() { num=std::sqrt(n); fuu(i,1,n) { in(a[i].val),a[i].bel=(i-1)/num+1,s[i]=a[i].val; e[a[i].bel].l=std::min(e[a[i].bel].l,i); e[a[i].bel].r=std::max(e[a[i].bel].r,i); } for(int i=1;i<=n;i+=num) std::sort(s+e[a[i].bel].l,s+e[a[i].bel].r+1); } inline void add(int l,int r,int c) { fuu(i,a[l].bel+1,a[r].bel-1) e[i].tag+=c; fuu(i,l,std::min(r,e[a[l].bel].r)) a[i].val+=c; fuu(i,e[a[l].bel].l,e[a[l].bel].r) s[i]=a[i].val; std::sort(s+e[a[l].bel].l,s+e[a[l].bel].r+1); if(a[l].bel!=a[r].bel) { fuu(i,std::max(l,e[a[r].bel].l),r) a[i].val+=c; fuu(i,e[a[r].bel].l,e[a[r].bel].r) s[i]=a[i].val; std::sort(s+e[a[r].bel].l,s+e[a[r].bel].r+1); } } inline int query(int l,int r,int c) { int ans=-inf; fuu(i,a[l].bel+1,a[r].bel-1) ans=std::max(ans,lob(e[i].l,e[i].r,c-e[i].tag,i)); fuu(i,l,std::min(r,e[a[l].bel].r)) if(a[i].val+e[a[i].bel].tag<c) ans=std::max(ans,a[i].val+e[a[i].bel].tag); if(a[l].bel!=a[r].bel) fuu(i,std::max(l,e[a[r].bel].l),r) if(a[i].val+e[a[i].bel].tag<c) ans=std::max(ans,a[i].val+e[a[i].bel].tag); return ans==-inf? -1:ans; } int main() { in(n); int p,l,r,c; init(); while(n--) { in(p),in(l),in(r),in(c); if(p==0) add(l,r,c); else printf("%d\n",query(l,r,c)); } return ~~(0^_^0); }