【題解】由乃打撲克

由乃打撲克

\(\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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章