bzoj3343: 教主的魔法 分块 标记
修改:两边暴力重构,中间打标记。复杂度:O(n0.5)
查询:中间二分两边暴力。O(n0.5logn0.5)
总时间复杂度O(n*n0.5logn0.5)
空间复杂度是n级别的
标记不用下传因为标记不用下传也没时间下传,如果在访问时下传就造成更棘手的不整块,如果累加式下传不好记录,所以就带着就行。
细节很多......
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #define MAXN 1010000 using namespace std; typedef long long LL; LL a[MAXN],b[1010][1010],mark[1010],n,pos[MAXN],lon,t; inline LL Min(LL x,LL y) { return x<y?x:y; } int comp(const int x,const int y) { return x>y; } inline void work1() { LL l,r,w; scanf("%lld%lld%lld",&l,&r,&w); LL z=pos[l]+1,y=pos[r]-1; for(LL i=z;i<=y;i++) mark[i]+=w; LL zzh=(pos[l]*lon); zzh=Min(zzh,r); for(LL i=l;i<=zzh;i++) a[i]+=w; zzh=pos[l]*lon; zzh=Min(zzh,n); memset(b[pos[r]],0,sizeof(b[pos[r]])); for(LL i=zzh-lon+1;i<=zzh;i++) b[pos[l]][i%lon+1]=a[i]; sort(b[pos[l]]+1,b[pos[l]]+lon+1); if(pos[l]!=pos[r]) { for(LL i=(pos[r]-1)*lon+1;i<=r;i++) a[i]+=w; zzh=pos[r]*lon; zzh=Min(zzh,n); memset(b[pos[r]],0,sizeof(b[pos[r]])); for(LL i=(pos[r]-1)*lon+1;i<=zzh;i++) b[pos[r]][i%lon+1]=a[i]; sort(b[pos[r]]+1,b[pos[r]]+lon+1); } } inline LL Count(LL p,LL c) { LL ans=0,l=1,r=lon; while(l<=r) { LL mid=(l+r)>>1; if(b[p][mid]+mark[p]<c) l=mid+1; else ans+=(r-mid+1),r=mid-1; } return ans; } inline void work2() { LL l,r,c,ans=0; scanf("%lld%lld%lld",&l,&r,&c); LL z=pos[l]+1,y=pos[r]-1; for(LL i=z;i<=y;i++) ans+=Count(i,c); LL zzh=(pos[l]*lon); zzh=Min(zzh,r); for(LL i=l;i<=zzh;i++) if(a[i]+mark[pos[i]]>=c) ans++; if(pos[l]!=pos[r]) { for(LL i=(pos[r]-1)*lon+1;i<=r;i++) if(a[i]+mark[pos[i]]>=c) ans++; } printf("%lld\n",ans); } int main() { scanf("%lld",&n); LL Q; scanf("%lld",&Q); lon=(LL)sqrt(n+0.5); for(LL i=1;i<=n;i++) { scanf("%lld",&a[i]); pos[i]=(i-1)/lon+1; b[pos[i]][i%lon+1]=a[i]; } t=pos[n]; for(int i=1;i<=t;i++) sort(b[i]+1,b[i]+lon+1); while(Q--) { char s[2]; scanf("%s",s); if(s[0]=='M')work1(); else work2(); } return 0; }
苟利国家生死以, 岂因祸福避趋之。