题目描述
传送门
题意:
1 l r x 将区间[l,r]的元素都+x
2 y 查询序列中是y这个数的坐标的最大差值
题解
分块之后对每一块排序然后每次查询的时候二分就行了
每一块维护一个add,整块打标记,剩余暴力修改
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define LL long long
#define N 500005
int n,m,opt,l,r,block,t,ans;
int L[N],R[N];
LL x,y;
LL a[N],b[N],add[N];
void init(int id)
{
for (int i=L[id];i<=R[id];++i) b[i]=a[i];
sort(b+L[id],b+R[id]+1);
}
void change(int l,int r,LL x)
{
int numl=(l-1)/block+1,numr=(r-1)/block+1;
if (numl==numr)
{
for (int i=l;i<=r;++i) a[i]+=x;
init(numl);
return;
}
if (l==L[numl]) l=numl;
else
{
for (int i=l;i<=R[numl];++i) a[i]+=x;
init(numl);
l=numl+1;
}
if (r==R[numr]) r=numr;
else
{
for (int i=L[numr];i<=r;++i) a[i]+=x;
init(numr);
r=numr-1;
}
for (int i=l;i<=r;++i) add[i]+=x;
}
int find(int l,int r,LL x)
{
while (l<=r)
{
int mid=(l+r)>>1;
if (b[mid]==x) {return mid;}
else if (b[mid]>x) r=mid-1;
else l=mid+1;
}
return -1;
}
int query(LL y)
{
int ansl=n,ansr=0;
for (int i=1;i<=t;++i)
{
int loc=find(L[i],R[i],y-add[i]);
if (loc==-1) continue;
for (int j=L[i];j<=R[i];++j)
if (a[j]+add[i]==y) {ansl=j;break;}
break;
}
for (int i=t;i>=1;--i)
{
int loc=find(L[i],R[i],y-add[i]);
if (loc==-1) continue;
for (int j=R[i];j>=L[i];--j)
if (a[j]+add[i]==y) {ansr=j;break;}
break;
}
if (ansl>ansr) return -1;
return ansr-ansl;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;++i) scanf("%I64d",&a[i]);
block=sqrt(n);t=(n-1)/block+1;
L[1]=1,R[1]=block;
for (int i=2;i<=t;++i) L[i]=L[i-1]+block,R[i]=R[i-1]+block;R[t]=n;
for (int i=1;i<=t;++i) init(i);
for (int i=1;i<=m;++i)
{
scanf("%d",&opt);
if (opt==1)
{
scanf("%d%d%I64d",&l,&r,&x);
if (l>r) swap(l,r);
change(l,r,x);
}
else
{
scanf("%I64d",&y);
ans=query(y);
printf("%d\n",ans);
}
}
}