题目大意:
给你一个序列,要求维护两种操作:
1,l,r,x: 在l到r这个区间将所有 值大于X的数减X
2, l,r,x 在l到r这个区间统计值等于X的数的个数。
N(序列长度<=10^5),max(a)(序列中的最大值<=10^5).
一道神题。
我们首先应该想到用数据结构优化,但是标记下传至底之前我们不好统计答案。
我们选择分块。
我们考虑如何对一整块进行1操作。
我们不妨对每一个块都统计其有几个X(X从1至10^5),并把值相同的元素串起来(用并查集维护)。
我们对1操作进行分析,我们发现每一次操作都会使极差减小,我们很难在严格的O(1)内维护1操作,那么我们可以通过摊还分析,让每次极差减小1的操作时间复杂度达到O(1)。
我们分情况讨论,若极差>=2x,那么我们就让最小的X个加上X,打上-X的懒标记,这个时候极差减少了X。
若极差<2X,我们让最大的那几个减X就好,这时候我们做了min(V,极差-x)次,极差小了min(V,极差-x)。
那么,我们就做好了。要更新边块(两侧的块)时,我们暴力修改,暴力重构就好了。
#pragma GCC optimize("-O3") #include<bits/stdc++.h> #define sight(c) (‘0‘<=c&&c<=‘9‘) #define SIZ 254 #define OTK 407 #define Re register #define N 100607 #define fp puts #define l(x) (x*SIZ-SIZ+1) #define r(x) (x*SIZ) inline void read(int &x){ static char c; for (c=getchar();!sight(c);c=getchar()); for (x=0;sight(c);c=getchar())x=x*10+c-48; } void write(int x){if (x<10) {putchar(‘0‘+x); return;} write(x/10); putchar(‘0‘+x%10);} inline void writeln(int x){ if (x<0) putchar(‘-‘),x*=-1; write(x); putchar(‘\n‘); } using namespace std; struct RR{int num,root;}V[OTK][N]; int pre[N],pos[N],a[N],ma[N],n,m,be[N],op,l,r,v,p,q,ans,lz[N]; inline int fa(int x){ while (x^pre[x]) x=pre[x]=pre[pre[x]]; return x; } inline void push(int x) { for (Re int i=l(x);i<=r(x);i++) a[i]=pos[fa(i)],V[x][a[i]].root=V[x][a[i]].num=0,a[i]-=lz[x]; for (int i=l(x);i<=r(x);i++) pre[i]=0; lz[x]=0; } inline void reb(int x){ ma[x]=0; for (Re int i=l(x);i<=r(x);i++) { if (a[i]>ma[x]) ma[x]=a[i]; V[x][a[i]].root?pre[i]=V[x][a[i]].root: (pos[i]=a[i],V[x][a[i]].root=i,pre[i]=i); V[x][a[i]].num++; } } RR *A,*B; void play(int x,int a,int b){ A=&V[x][a]; B=&V[x][b]; B->root?pre[A->root]=B->root:(B->root=A->root,pos[A->root]=b); B->num+=A->num,A->num=A->root=0; } inline void det(int x,int v){ int &p=lz[x] ,&q=ma[x]; if ((v<<1)<=q-p) { for (Re int i=p+1;i<=p+v;i++) if (V[x][i].root) play(x,i,i+v); p+=v; } else { for (Re int i=q;i>p+v;i--) if (V[x][i].root) play(x,i,i-v); q=min(q,p+v); } } int main () { read(n); read(m); for (Re int i=1;i<=n;i++) read(a[i]),be[i]=(i-1)/SIZ+1; for (Re int i=1;i<=be[n];i++) reb(i); while (m--) { read(op); read(l); read(r); read(v); switch (op) { case 1: p=be[l]; q=be[r]; if (p^q) { push(p); push(q); for (Re int i=l;i<=r(p);i++) if (a[i]>v) a[i]-=v; for (Re int i=l(q);i<=r;i++) if (a[i]>v) a[i]-=v; for (Re int i=p+1;i<q;i++) det(i,v); reb(p); reb(q); } else { push(p); for (Re int i=l;i<=r;i++) if (a[i]>v) a[i]-=v; reb(p); } break; case 2: p=be[l]; q=be[r]; ans=0; if (p^q) { for (Re int i=l;i<=r(p);i++) if (pos[fa(i)]-lz[p]==v) ans++; for (Re int i=l(q);i<=r;i++) if (pos[fa(i)]-lz[q]==v) ans++; for (Re int i=p+1;i<q;i++) if (v+lz[i]<N) ans+=V[i][v+lz[i]].num; }else for (Re int i=l;i<=r;i++) if (pos[fa(i)]-lz[p]==v) ans++; writeln(ans); break; } } }