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