题意
给你一段序列,并且有两种操作
操作①:将序列中从l-r每个元素加上x
操作②:在序列中找到ai=aj=y,j-i的最大值,如果找不到则输出-1
思路
直接分块暴力即可
对于区间加,普通标记加暴力即可
对于找最大值,直接在每个块中二分找y,找不到即为-1
代码
#include<iostream>
#include<algorithm>
#include<set>
#include<cmath>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn=5e5+10;
ll n,blo,tot;
ll a[maxn];//bl数组记录属于哪个块
int bel[maxn],m;
ll tag[maxn];//维护区间加标记
vector <ll> vc[maxn];
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++){
int pos=lower_bound(vc[i].begin(),vc[i].end(),y-tag[i])-vc[i].begin();
if(y-tag[i] == vc[i][pos]){
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--){
int pos=lower_bound(vc[i].begin(),vc[i].end(),y-tag[i])-vc[i].begin();
if(y-tag[i] == vc[i][pos]){
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 q,l,r,y,op;
scanf("%lld%d",&n,&q);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
build();
for(int i=1;i<=q;i++){
scanf("%d",&op);
if(op==1){
scanf("%d%d%d",&l,&r,&y);
add(l,r,y);
}
else{
scanf("%d",&y);
printf("%d\n",query(y));
}
}
return 0;
}