题意:给定一段数字序列,两个操作,操作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;
}