CF 551E. GukiZ and GukiZiana [分块 二分]
题意:
区间加 给出$y$查询$a_i=a_j=y$的$j-i$最大值
一开始以为和论文CC题一样...然后发现他带修改并且是给定了值
这样就更简单了....
每个块维护排好序的结果
修改暴力重构+整块打标记
查询暴力查+整块二分找数量
复杂度$O(SlogS + \frac{N}{S} + S+\frac{N}{S}logS)$
woc求了一节课导数也没求出最值来又发现一开始式子列错了不管了我就开根号了..(我才不会说是因为乱搞了一下更慢了)
貌似是因为用pair上瘾的原因吧常数比较大....感觉zyf2000的写法不科学反而更快
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> using namespace std; typedef long long ll; #define pii pair<ll,int> #define MP make_pair #define fir first #define sec second const int N=5e5+5,M=710,INF=1e9; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int n,Q,op,x,y; ll a[N]; int block,pos[N],m; struct _Blo{ int l,r,n; pii a[M]; pii& operator [](int x) {return a[x];} }b[M]; void ini(){ block=sqrt(n); m=(n-1)/block+1; for(int i=1;i<=n;i++) pos[i]=(i-1)/block+1; for(int i=1;i<=m;i++) b[i].l=(i-1)*block+1, b[i].r=i*block; b[m].r=n; } struct Block{ ll add[N]; void Set(int x){ _Blo &t=b[x]; t.n=0; for(int i=t.l ; i<=t.r ; i++) t[++t.n]=MP(a[i],i); sort(t.a+1 , t.a+t.n+1); } void Add(int l,int r,int v){ int pl=pos[l],pr=pos[r]; if(pl==pr){ for(int i=l;i<=r;i++) a[i]+=v; Set(pl); }else{ for(int i=l ; i<=b[pl].r ; i++) a[i]+=v; Set(pl); for(int i=b[pr].l ; i<=r ; i++) a[i]+=v; Set(pr); for(int i=pl+1;i<pr;i++) add[i]+=v; } } int Que(ll v){ int l=INF,r=0; for(int x=1;x<=m;x++){ _Blo &t=b[x]; int p=lower_bound(t.a+1 , t.a+t.n+1 , MP(v-add[x],0) ) - t.a, q=upper_bound(t.a+1 , t.a+t.n+1 , MP(v-add[x],INF) ) - t.a; if(t[p].fir==v-add[x]) l=min(l,t[p].sec), r=max(r,t[q-1].sec); } return r-l==-INF ? -1 : r-l; } }B; int main(){ //freopen("in","r",stdin); n=read();Q=read(); ini(); for(int i=1;i<=n;i++) a[i]=read(); for(int i=1;i<=m;i++) B.Set(i); while(Q--){ op=read(); if(op==1) x=read(),y=read(),B.Add(x,y,read()); else printf("%d\n",B.Que(read()) ); } }
Copyright:http://www.cnblogs.com/candy99/