cf E. GukiZ and GukiZiana

E. GukiZ and GukiZiana

题意:给定一段数字序列,两个操作,操作1将l->r的区间内的数全部加上某一个值,

  操作2:查询>>找到aj=ai=v,使得max(j-i),并输出

思路:查询某个值的时候>>可以暴力从前后分别查询>>>找到最后一个,和最前面的一个

  同时考虑到同时加上某一个值区间内的大小顺序不变

  考虑到优化分块>>>tag[i]表示第i块需要加上去的值>>同时在开一个数组,存储每个数组排序之后的序列

  修改的时候>>暴力修改每一个块>>不足一个块的暴力修改(srqt(n));

  查询的时候>>从第一个块开始查询>>二分查找>>当找到时然后暴力在这个区间内进行寻找>> 复杂度sqrt(n)log(sqrt(n))

  不得不说分块大法真的时暴力啊>>>感觉好无脑>>>

  

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
typedef long long ll;
ll a[N];int bel[N],tot;ll tag[N];
vector<ll>vc[N];int n,m,blo;
void build(){
	blo=sqrt(n);
	tot=n/blo;if(n%blo) tot++;
	for(int i=1;i<=n;i++) bel[i]=(i-1)/blo+1,vc[bel[i]].push_back(a[i]);
	for(int i = 1; i <= tot; i++){
        sort(vc[i].begin(),vc[i].end());
    }
}
void reset(int x){
	vc[x].clear();
	for(int i=(x-1)*blo+1;i<=x*blo;i++) vc[x].push_back(a[i]);
	sort(vc[x].begin(),vc[x].end());
}
void add(int l,int r,int x){
	int b1=bel[l],b2=bel[r];
	if(b1==b2){
		for(int i=l;i<=r;i++) a[i]+=x;
		reset(b1);
	}
	else{
		for(int i=l;i<=b1*blo;i++) a[i]+=x;
		reset(b1);
		for(int i=b1+1;i<b2;i++) tag[i]+=x;
		for(int i=(b2-1)*blo+1;i<=r;i++) a[i]+=x;
		reset(b2);
	}
}
int query(int y){
	int l=0,r=0;
	for(int i=1;i<=tot;i++){
		auto pos=lower_bound(vc[i].begin(),vc[i].end(),y-tag[i]);
		if(pos!=vc[i].end()&&*pos==y-tag[i]){
			for(int j=(i-1)*blo+1;j<=i*blo;j++){
				if(a[j]+tag[i]==y) {l=j;break;}
			}
			break;
		}
	}
	if(l==0) return -1;
	for(int i=tot;i>=1;i--){
		auto pos=lower_bound(vc[i].begin(),vc[i].end(),y-tag[i]);
		if(pos!=vc[i].end()&&*pos==y-tag[i]){
			for(int j=i*blo;j>(i-1)*blo;j--){
				if(a[j]+tag[i]==y) {r=j;break;}
			}
			break;
		}
	}
	return r-l;
}
int main(){
	int cas,l,r,v;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%I64d",&a[i]);
	build();
	while(m--){
		scanf("%d",&cas);
		if(cas==1){
			scanf("%d%d%d",&l,&r,&v);
			add(l,r,v);
		}
		else{
			scanf("%d",&v);
			int ans=query(v);
			printf("%d\n",ans);
		}
	}
	return 0;
} 

  

猜你喜欢

转载自www.cnblogs.com/vainglory/p/9177573.html