[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
  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){
 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)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;jquery(j,x);
102             }
103             printf("%d\n",ans);
104         }
105     }
106     return 0;
107 }