[cf896E]Welcome home, Chtholly
将序列分块,对每一个块维护以下信息:
1.块内的最大值$\max$和区间减的懒标记
2.存在的权值(包含即可)以及对应元素的链表(首尾、长度)
对于散块修改/询问,可以利用2重构序列,即可$o(\sqrt{n})$修改/询问
对于整块修改,注意到最大值单调不降,因此在$o(\Delta \max)$的复杂度内实现即可
具体的,对于$x$和$\max$的关系分类讨论:
1.若$\max\le x$,显然操作无意义
2.若$\max \le 2x$,将$(x,\max]$对应的链表起点重新记录,并重算最大值(不断减小)
3.若$2x<\max $,通过区间减的懒标记,变为将$[1,x]$中的元素加$x$,进而做法类似2
对于整块查询,利用2对应的长度信息即可
时间复杂度为$o(n+V\sqrt{n}+m\sqrt{n})$(其中$V$为值域),可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 #define M 350 5 vector<int>v[M]; 6 int n,m,K,p,l,r,x,ans,a[N],bl[N],st[M],ed[M],mx[M],tag[M],nex[N]; 7 struct Link{ 8 int h,t,len; 9 Link(){ 10 h=t=len=0; 11 } 12 bool empty(){ 13 return !len; 14 } 15 void add(int k){ 16 if (empty())h=k; 17 else nex[t]=k; 18 t=k,len++; 19 } 20 void add(Link k){ 21 if (k.empty())return; 22 if (empty())h=k.h; 23 else nex[t]=k.h; 24 t=k.t,len+=k.len; 25 } 26 }L[M][N]; 27 void build_a(int k){ 28 for(int i=0;i<v[k].size();i++){ 29 if (L[k][v[k][i]].empty())continue; 30 for(int j=L[k][v[k][i]].h;;j=nex[j]){ 31 a[j]=v[k][i]; 32 if (j==L[k][v[k][i]].t)break; 33 } 34 L[k][v[k][i]]=Link(); 35 } 36 for(int i=st[k];i<=ed[k];i++)a[i]-=tag[k],nex[i]=0; 37 mx[k]=tag[k]=0,v[k].clear(); 38 } 39 void build_info(int k){ 40 for(int i=st[k];i<=ed[k];i++){ 41 mx[k]=max(mx[k],a[i]); 42 v[k].push_back(a[i]),L[k][a[i]].add(i); 43 } 44 } 45 void update(int l,int r,int x){ 46 build_a(bl[l]); 47 for(int i=l;i<=r;i++) 48 if (a[i]>x)a[i]-=x; 49 build_info(bl[l]); 50 } 51 void update(int k,int x){ 52 if (mx[k]<=x)return; 53 if (mx[k]<=(x<<1)){ 54 for(int i=x+tag[k]+1;i<=mx[k]+tag[k];i++) 55 if (!L[k][i].empty()){ 56 if (L[k][i-x].empty())v[k].push_back(i-x); 57 L[k][i-x].add(L[k][i]),L[k][i]=Link(); 58 } 59 while (L[k][mx[k]+tag[k]].empty())mx[k]--; 60 return; 61 } 62 for(int i=tag[k]+1;i<=x+tag[k];i++) 63 if (!L[k][i].empty()){ 64 if (L[k][i+x].empty())v[k].push_back(i+x); 65 L[k][i+x].add(L[k][i]),L[k][i]=Link(); 66 } 67 tag[k]+=x,mx[k]-=x; 68 } 69 int query(int l,int r,int x){ 70 build_a(bl[l]),build_info(bl[l]); 71 int ans=0; 72 for(int i=l;i<=r;i++) 73 if (a[i]-tag[bl[l]]==x)ans++; 74 return ans; 75 } 76 int query(int k,int x){ 77 if (x+tag[k]>=N)return 0; 78 return L[k][x+tag[k]].len; 79 } 80 int main(){ 81 scanf("%d%d",&n,&m),K=(int)sqrt(n); 82 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 83 for(int i=1;i<=n;i++)bl[i]=(i-1)/K+1; 84 for(int i=1;i<=bl[n];i++){ 85 st[i]=(i-1)*K+1,ed[i]=min(i*K,n); 86 build_info(i); 87 } 88 for(int i=1;i<=m;i++){ 89 scanf("%d%d%d%d",&p,&l,&r,&x); 90 if (p==1){ 91 if (bl[l]==bl[r])update(l,r,x); 92 else{ 93 update(l,ed[bl[l]],x),update(st[bl[r]],r,x); 94 for(int j=bl[l]+1;j<bl[r];j++)update(j,x); 95 } 96 } 97 if (p==2){ 98 if (bl[l]==bl[r])ans=query(l,r,x); 99 else{ 100 ans=query(l,ed[bl[l]],x)+query(st[bl[r]],r,x); 101 for(int j=bl[l]+1;j<bl[r];j++)ans+=query(j,x); 102 } 103 printf("%d\n",ans); 104 } 105 } 106 return 0; 107 }