题意:给出一个数列,要求支持以下两种操作,1)给某区间内的所有数都加上x,2)输出数列中等于y的两个数的最大距离。
比赛的时候没想到这是分块(花式暴力。。),以为是线段书啥的,然后不会。。赛后听说是分块,其实思路一下就想到了(以前照书抄过一个分块题)。。。。然而第一次写的时候脑残完全写错了,发现的时候汗啊。。全删了重写,又写了一个小时左右,wa了两次,修正了两个bug,过了。。。分成若干块,如果改变的区间完全包含一个块,那就直接给总的val加x,不完全包含就o(n)直接处理,查询的时候是二分,其实这个题还是比较简单的分块,因为查询没有区间问题,就是从头到尾,否则查询也比较麻烦。
#include<iostream> #include<map> #include<algorithm> #include<cstdio> #include<cstring> #include<cstdlib> #include<vector> #include<queue> #include<stack> #include<functional> #define pb push_back using namespace std; typedef long long ll; const int maxv=5e5+40; const int sz=1000; struct Num{ ll o,v; bool operator < (const Num &C)const{ if(v!=C.v) return v<C.v; else return o<C.o; } }; vector<Num> bucket[1000]; ll a[maxv]; ll val[maxv]; int n,q; void update(int l,int r,ll x){ if(l/sz==r/sz){ for(int i=l;i<=r;i++) a[i]+=x; bucket[l/sz].clear(); for(int i=l/sz*sz;i<l/sz*sz+sz;i++) bucket[l/sz].pb((Num){i,a[i]}); sort(bucket[l/sz].begin(),bucket[l/sz].end()); }else{ for(int i=l/sz+1;i<r/sz;i++) val[i]+=x; update(l,l/sz*sz+sz-1,x); update(r/sz*sz,r,x); } return; } bool cmp(Num a,Num b){ return a.v<b.v; } int quaryl(ll y){ for(int i=0;i<=n/sz;i++){ Num tar; tar.v=y-val[i]; vector<Num>::iterator it=lower_bound(bucket[i].begin(),bucket[i].end(),tar,cmp); if(it!=bucket[i].end()&&(*it).v==tar.v){ return (*it).o; } } return -1; } int queryr(ll y){ for(int i=n/sz;i>=0;i--){ Num tar; tar.v=y-val[i]; vector<Num>::iterator it=upper_bound(bucket[i].begin(),bucket[i].end(),tar,cmp); if(it!=bucket[i].begin()&&(*(it-1)).v==tar.v){ return (*(it-1)).o; } } return -1; } int main(){ ////freopen("/home/files/CppFiles/in","r",stdin); cin>>n>>q; for(int i=0;i<n;i++){ scanf("%I64d",&a[i]); bucket[i/sz].pb((Num){i,a[i]}); } for(int i=0;i<=n/sz;i++) sort(bucket[i].begin(),bucket[i].end()); while(q--){ int type; scanf("%d",&type); if(type==1){ int l,r,x; scanf("%d%d%d",&l,&r,&x); update(l-1,r-1,x); }else{ int y; scanf("%d",&y); int l=quaryl(y); if(l!=-1){ printf("%d ",queryr(y)-l); }else{ puts("-1"); } } } return 0; }