【题解】由乃打扑克

由乃打扑克

( ext{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++='
';
}
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;
}
原文地址:https://www.cnblogs.com/h-lka/p/15362744.html