思路:分块。分成sqrt(n)个块,将每个块里的数存入vector中,排序。更新时,对于残缺的块,暴力更新即可,完整的块可以加懒惰标记;查询时类似,对于残缺的块暴力查找,完整的块利用二分。(代码有点丑。。)
#include<bits/stdc++.h>
using namespace std;
const int MAX=1e5+10;
typedef long long ll;
int siz,cnt,n;
int b[MAX];
ll lazy[400];
struct lenka
{
ll x,y;
}a[MAX];
vector<lenka>v[400];
int cmp(const lenka& p,const lenka& q)
{
if(p.y==q.y)return p.x<q.x;
return p.y<q.y;
}
void build() //初始化建块
{
siz=sqrt(n);
cnt=n/siz;
if(n%siz)cnt++;
for(int i=1;i<=n;i++)
{
b[i]=(i-1)/siz+1;
v[b[i]].push_back(a[i]);
}
for(int i=1;i<=cnt;i++)sort(v[i].begin(),v[i].end(),cmp);
}
void rebuild(int th) //暴力更新残缺块
{
v[th].clear();
for(int i=(th-1)*siz+1;i<=th*siz&&i<=n;i++)v[th].push_back(a[i]);
sort(v[th].begin(),v[th].end(),cmp);
}
int up(int th,int l,int r,ll x)//二分查找上限
{
int ans=0;
while(r>=l)
{
int mid=(l+r)/2;
if(v[th][mid].y>x)r=mid-1;
else
{
ans=mid;
l=mid+1;
}
}
if(v[th][ans].y==x)return v[th][ans].x;
return -1;
}
int low(int th,int l,int r,ll x)//二分查找下限
{
int ans=0;
while(r>=l)
{
int mid=(l+r)/2;
if(v[th][mid].y>=x)
{
ans=mid;
r=mid-1;
}
else l=mid+1;
}
if(v[th][ans].y==x)return v[th][ans].x;
return -1;
}
int main()
{
int m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i].y);
a[i].x=i;
}
build();
while(m--)
{
int op;
scanf("%d",&op);
if(op==1)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
for(int i=x;i<=y&&i<=b[x]*siz;i++)a[i].y+=z;
rebuild(b[x]);
for(int i=b[x]+1;i*siz<=y;i++)lazy[i]+=z;
if(b[x]!=b[y]&&y%siz)
{
for(int i=(b[y]-1)*siz+1;i<=y;i++)a[i].y+=z;
rebuild(b[y]);
}
}
else
{
ll x;
scanf("%lld",&x);
int l=-1,r=-2;
for(int i=1;i<=cnt;i++)
{
int index=low(i,0,v[i].size()-1,x-lazy[i]);
if(index!=-1)
{
l=index;
break;
}
}
for(int i=cnt;i>=1;i--)
{
int index=up(i,0,v[i].size()-1,x-lazy[i]);
if(index!=-1)
{
r=index;
break;
}
}
printf("%d\n",r-l);
}
}
return 0;
}