\(\text{Solution:}\)
題目就是區間加,求區間第 \(k\) 小。這裏沒有用時間分治的做法。
考慮每次修改的時候,如果遇到散塊就暴力重構,整塊打標記。
詢問的時候直接二分答案,整塊裏面用 lower_bound,
對於散塊:
如果我們暴力做,複雜度是錯誤的,這樣是根號外面帶了兩個 \(\log.\) 所以我們不能暴力處理。
考慮直接把散塊拉出來。但是,由於我們需要保證塊內有序,所以我們需要排序,但如果使用 sort
這樣排序複雜度和塊大小有關,不好平衡。
發現兩個散塊都是有序的,直接雙指針歸併合併。這樣複雜度就是對的了。
考慮修改的時候,同樣對於散塊重構的時候還是需要歸併,同樣的道理會使得複雜度爆炸。
對於塊長,本題中用了 \(\frac{n}{128}\) 的大小卡了過去。當然這個塊長嚴重不符合理論大小。
學到的東西:
-
複雜度平衡排序不能和塊長有關係,否則平衡的複雜度會炸掉。
-
char obuf[1<<21],*O=buf;Fwrite(int x){if(x>9)Fwrite(x/10);*O++=x%10+'0';} fwrite(obuf,O-obuf,1,stdout)
超級快輸
*一種雙指針寫法 vector
:
vector<pr>::iterator ll=vt.begin();
vector<pr>::iterator rr=pt.begin();
for(;ll!=vt.end()||rr!=pt.end();){
pr I,J;
if(ll==vt.end()&&rr==pt.end())break;
if(ll!=vt.end()) I=*ll;
else I=mk(100000000ll,100000000ll);
if(rr!=pt.end()) J=*rr;
else J=mk(100000000ll,100000000ll);
if((ll==vt.end())||(rr!=pt.end()&&J<I)){
Ans.push_back(J);
++rr;
}
else{
Ans.push_back(I);
++ll;
}
}
#include<bits/stdc++.h>
using namespace std;
const int N=200010;
const int SN=128;
int n,m,a[N];
char buf[1<<21],*p1=buf,*p2=buf;
char obuf[1<<21],*O=obuf;
void Fwrite(int x){
int fg=1;
if(x<0)x=-x,*O++='-';
if(x>9)Fwrite(x/10);
*O++=x%10+'0';
}
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
inline int read() {
int s=0,w=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')w=-1;
ch=getchar();
}
while(isdigit(ch)){
s=s*10+ch-'0';
ch=getchar();
}
return s*w;
}
typedef pair<int,int> pr;
#define mk make_pair
#define fi first
#define se second
inline bool cmp(const pr&A,const pr&B){return A.fi<B.fi;}
int B,id[N];
vector<pr>bk[N];
int tag[N];
inline int Min(int x,int y){return x<y?x:y;}
vector<pr> St(vector<pr> vec,int l,int r,int v){
vector<pr>vt;
vector<pr>pt;
vector<pr>Ans;
for(int i=0;i<(int)vec.size();++i){
if(vec[i].se>=l&&vec[i].se<=r){
pt.push_back(mk(vec[i].fi+v,vec[i].se));
}
else vt.push_back(mk(vec[i].fi,vec[i].se));
}
vector<pr>::iterator ll=vt.begin();
vector<pr>::iterator rr=pt.begin();
for(;ll!=vt.end()||rr!=pt.end();){
pr I,J;
if(ll==vt.end()&&rr==pt.end())break;
if(ll!=vt.end()) I=*ll;
else I=mk(100000000ll,100000000ll);
if(rr!=pt.end()) J=*rr;
else J=mk(100000000ll,100000000ll);
if((ll==vt.end())||(rr!=pt.end()&&J<I)){
Ans.push_back(J);
++rr;
}
else{
Ans.push_back(I);
++ll;
}
}
return Ans;
}
void change(int l,int r,int v){
if(id[l]!=id[r]){
bk[id[l]]=St(bk[id[l]],l,r,v);
bk[id[r]]=St(bk[id[r]],l,r,v);
for(int i=id[l]+1;i<id[r];++i)tag[i]+=v;
return;
}
bk[id[l]]=St(bk[id[l]],l,r,v);
}
vector<pr>obk;
bool check(int l,int r,int v,int k){
int cnt=0;
for(int i=id[l]+1;i<id[r];++i){
int pos=lower_bound(bk[i].begin(),bk[i].end(),mk(v-tag[i],0))-bk[i].begin();
cnt+=pos;
}
int pos=lower_bound(obk.begin(),obk.end(),mk(v,0))-obk.begin();
cnt+=pos;
return cnt<k;
}
void query(int l,int r,int v){
if(v>(r-l+1)){
puts("-1");
return;
}
int L=-2e9,R=2e9;
int ans=-1;
obk.clear();
if(id[l]!=id[r]){
vector<pr>::iterator i=bk[id[l]].begin();
vector<pr>::iterator j=bk[id[r]].begin();
for(;i!=bk[id[l]].end()||j!=bk[id[r]].end();){
pr I=*i;
pr J=*j;
I.first+=tag[id[l]];
J.first+=tag[id[r]];
if((i==bk[id[l]].end())||(j!=bk[id[r]].end()&&J<I)){
if(J.se>=l&&J.se<=r)obk.push_back(J);
++j;
}
else {
if(I.se>=l&&I.se<=r)obk.push_back(I);
++i;
}
}
}
else{
for(int i=0;i<Min(B,(int)bk[id[l]].size());++i){
pr X=bk[id[l]][i];
X.first+=tag[id[l]];
if(bk[id[l]][i].se>=l&&bk[id[l]][i].se<=r)obk.push_back(X);
}
}
while(L<=R){
long long mid=(L+R)>>1;
if(check(l,r,mid,v))ans=mid,L=mid+1;
else R=mid-1;
}
Fwrite(ans);
*O++='\n';
}
signed main(){
freopen("in.txt","r",stdin);
freopen("My.out","w",stdout);
n=read();m=read();
for(int i=1;i<=n;++i)a[i]=read();
B=(n-1)/SN+1;//2450
for(int i=1;i<=n;++i){
id[i]=((i-1)/B)+1;
bk[id[i]].push_back(mk(a[i],i));
}
for(int i=1;i<=(n/B)+1;++i){stable_sort(bk[i].begin(),bk[i].end(),cmp);}
for(int i=1;i<=m;++i){
int opt=read(),l=read(),r=read(),k=read();
if(opt==2)change(l,r,k);
else query(l,r,k);
}
fwrite(obuf,O-obuf,1,stdout);
return 0;
}