【题解】由乃打扑克
\(\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;
}